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.

304 lines
11 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 F = Format
(** Utility methods to support the translation of clang ast constructs into sil instructions. *)
type continuation =
{ break: Procdesc.Node.t list
; continue: Procdesc.Node.t list
; return_temp: bool
(** true if temps should not be removed in the node but returned to ancestors *) }
(** Whether we are collecting instructions for a new block in the CFG ([Busy]) or there are no
blocks being created from enclosing translations ([Free]) *)
type priority_node =
| Free (** no node currently being created *)
| Busy of Clang_ast_t.pointer
(** the translation of the clang expression or statement at [pointer] will create a node with
the collected instructions from the sub-expressions (see {!control.instrs} *)
(** The input of the translation constructed from enclosing expressions. *)
type trans_state =
{ context: CContext.t (** global context of the translation *)
; succ_nodes: Procdesc.Node.t list
(** successor nodes in the CFG, i.e. instructions that will happen *after* the current
expression or statement being translated (note that the CFG is constructed bottom-up,
starting from the last instructions) *)
; continuation: continuation option
(** current continuation, used for [break], [continue], and the like *)
; priority: priority_node (** see {!priority_node} *)
; var_exp_typ: (Exp.t * Typ.t) option
(** the expression (usually of the form [Exp.Lvar pvar]) that the enclosing expression or
statement is trying to initialize, if any *)
; opaque_exp: (Exp.t * Typ.t) option (** needed for translating [OpaqueValueExpr] nodes *)
; is_fst_arg_objc_instance_method_call: bool
; passed_as_noescape_block_to: Procname.t option }
val pp_trans_state : F.formatter -> trans_state -> unit
val default_trans_state : CContext.t -> trans_state
(** Part of the translation result that is (loosely) related to control flow graph construction.
More importantly, this is the part of a [trans_result] that some internal translation functions
work on when constructing a [trans_result] before the other components of the translation result
are available (such as the return expression). This is made into a separate type to make
intermediate computations easier to write and easier to typecheck. *)
type control =
{ root_nodes: Procdesc.Node.t list (** Top cfg nodes (root) created by the translation *)
; leaf_nodes: Procdesc.Node.t list (** Bottom cfg nodes (leaf) created by the translate *)
; instrs: Sil.instr list
(** Instructions that need to be placed in the current CFG node being constructed, *after*
[leaf_nodes]. *)
; initd_exps: Exp.t list (** list of expressions that are initialized by the instructions *)
; cxx_temporary_markers_set: Pvar.t list
(** markers for C++ temporaries that have been set during the translation; used to avoid
adding the same marker several times *) }
val pp_control : F.formatter -> control -> unit
(** A translation result. It is returned by the translation function. *)
type trans_result =
{ control: control
; return: Exp.t * Typ.t (** value returned by the translated statement *)
; method_name: Procname.t option
(** in the specific case of translating a method call in C++, we get the method name called
at the same time we get the [this] object that contains the method. The [this] instance
object is returned as the [return] field, while the method to call is filled in here.
This field is [None] in all other cases. *)
; is_cpp_call_virtual: bool }
val empty_control : control
val mk_trans_result :
?method_name:BuiltinDecl.t
-> ?is_cpp_call_virtual:bool
-> Exp.t * Typ.t
-> control
-> trans_result
val undefined_expression : unit -> Exp.t
val collect_controls : Procdesc.t -> control list -> control
(** Collect the results of translating a list of instructions, and link up the nodes created. *)
val collect_trans_results : Procdesc.t -> return:Exp.t * Typ.t -> trans_result list -> trans_result
val is_return_temp : continuation option -> bool
val mk_cond_continuation : continuation option -> continuation option
val define_condition_side_effects :
Exp.t * Typ.t -> Sil.instr list -> Location.t -> (Exp.t * Typ.t) * Sil.instr list
val source_range_of_stmt : Clang_ast_t.stmt -> Clang_ast_t.source_range
val extract_stmt_from_singleton :
Clang_ast_t.stmt list -> Clang_ast_t.source_range -> string -> Clang_ast_t.stmt
val is_null_stmt : Clang_ast_t.stmt -> bool
val dereference_var_sil : Exp.t * Typ.t -> Location.t -> Sil.instr * Exp.t
val dereference_value_from_result :
?strip_pointer:bool -> Clang_ast_t.source_range -> Location.t -> trans_result -> trans_result
(** Given a [trans_result], create a temporary variable with dereferenced value of an expression
assigned to it *)
val cast_operation :
?objc_bridge_cast_kind:Clang_ast_t.obj_c_bridge_cast_kind
-> Clang_ast_t.cast_kind
-> Exp.t * Typ.t
-> Typ.t
-> Location.t
-> Sil.instr list * (Exp.t * Typ.t)
val trans_assertion : trans_state -> Location.t -> trans_result
val contains_opaque_value_expr : Clang_ast_t.stmt -> bool
val builtin_trans :
trans_state
-> Clang_ast_t.source_range
-> Location.t
-> trans_result list
-> Procname.t
-> trans_result option
val cxx_method_builtin_trans :
trans_state
-> Clang_ast_t.source_range
-> Location.t
-> trans_result list
-> Procname.t
-> trans_result option
val new_or_alloc_trans :
trans_state
-> Location.t
-> Clang_ast_t.stmt_info
-> Clang_ast_t.qual_type
-> Typ.Name.t option
-> string
-> trans_result
val cpp_new_trans :
Typ.IntegerWidths.t -> Location.t -> Typ.t -> Exp.t option -> (Exp.t * Typ.t) list -> trans_result
(** Module for creating cfg nodes and other utility functions related to them. *)
module Nodes : sig
val is_binary_assign_op : Clang_ast_t.binary_operator_info -> bool
val create_prune_node :
Procdesc.t
-> branch:bool
-> negate_cond:bool
-> Exp.t
-> Sil.instr list
-> Location.t
-> Sil.if_kind
-> Procdesc.Node.t
val is_true_prune_node : Procdesc.Node.t -> bool
end
(** priority_node is used to enforce some kind of policy for creating nodes in the cfg. Certain
elements of the AST _must_ create nodes therefore there is no need for them to use
priority_node. Certain elements instead need or need not to create a node depending of certain
factors. When an element of the latter kind wants to create a node it must claim priority first
(like taking a lock). priority can be claimes only when it is free. If an element of AST
succedes in claiming priority its id (pointer) is recorded in priority. After an element has
finished it frees the priority. In general an AST element E checks if an ancestor has claimed
priority. If priority is already claimed E does not have to create a node. If priority is free
then it means E has to create the node. Then E claims priority and release it afterward. *)
module PriorityNode : sig
type t = priority_node
val is_priority_free : trans_state -> bool
val try_claim_priority_node : trans_state -> Clang_ast_t.stmt_info -> trans_state
val force_claim_priority_node : trans_state -> Clang_ast_t.stmt_info -> trans_state
val own_priority_node : t -> Clang_ast_t.stmt_info -> bool
val compute_controls_to_parent :
trans_state
-> Location.t
-> Procdesc.Node.stmt_nodekind
-> Clang_ast_t.stmt_info
-> control list
-> control
(** Used by translation functions to handle potential cfg nodes. It connects nodes returned by the
translation of stmt children and deals with creating or not a cfg node depending of owning the
priority_node. It returns the [control] that should be passed to the parent. *)
val compute_control_to_parent :
trans_state
-> Location.t
-> Procdesc.Node.stmt_nodekind
-> Clang_ast_t.stmt_info
-> control
-> control
(** like [compute_controls_to_parent] but for a singleton, so the only possible effect is creating
a node *)
val compute_results_to_parent :
trans_state
-> Location.t
-> Procdesc.Node.stmt_nodekind
-> Clang_ast_t.stmt_info
-> return:Exp.t * Typ.t
-> trans_result list
-> trans_result
(** convenience wrapper around [compute_controls_to_parent] *)
val compute_result_to_parent :
trans_state
-> Location.t
-> Procdesc.Node.stmt_nodekind
-> Clang_ast_t.stmt_info
-> trans_result
-> trans_result
(** convenience function like [compute_results_to_parent] when there is a single [trans_result] to
consider *)
val force_sequential :
Location.t
-> Procdesc.Node.stmt_nodekind
-> trans_state
-> Clang_ast_t.stmt_info
-> mk_first_opt:(trans_state -> Clang_ast_t.stmt_info -> trans_result option)
-> mk_second:(trans_state -> Clang_ast_t.stmt_info -> trans_result)
-> mk_return:(fst:trans_result -> snd:trans_result -> Exp.t * Typ.t)
-> trans_result
val force_sequential_with_acc :
Location.t
-> Procdesc.Node.stmt_nodekind
-> trans_state
-> Clang_ast_t.stmt_info
-> mk_first:(trans_state -> Clang_ast_t.stmt_info -> trans_result * 'a)
-> mk_second:('a -> trans_state -> Clang_ast_t.stmt_info -> trans_result)
-> mk_return:(fst:trans_result -> snd:trans_result -> Exp.t * Typ.t)
-> trans_result
end
(** Module for translating goto instructions by keeping a map of labels. *)
module GotoLabel : sig
val find_goto_label : CContext.t -> string -> Location.t -> Procdesc.Node.t
end
(** Module that provides utility functions for translating different types of loops. *)
module Loops : sig
type loop_kind =
| For of
{ init: Clang_ast_t.stmt
; decl_stmt: Clang_ast_t.stmt
; condition: Clang_ast_t.stmt
; increment: Clang_ast_t.stmt
; body: Clang_ast_t.stmt }
| While of
{decl_stmt: Clang_ast_t.stmt option; condition: Clang_ast_t.stmt; body: Clang_ast_t.stmt}
| DoWhile of {condition: Clang_ast_t.stmt; body: Clang_ast_t.stmt}
val get_cond : loop_kind -> Clang_ast_t.stmt
val get_body : loop_kind -> Clang_ast_t.stmt
end
(** This module handles the translation of the variable self which is challenging because self is
used both as a variable in instance method calls and also as a type in class method calls. *)
module Self : sig
val add_self_parameter_for_super_instance :
Clang_ast_t.stmt_info
-> CContext.t
-> Procname.t
-> Location.t
-> Clang_ast_t.obj_c_message_expr_info
-> trans_result option
val is_var_self : Pvar.t -> bool -> bool
end
val is_logical_negation_of_int :
Tenv.t -> Clang_ast_t.expr_info -> Clang_ast_t.unary_operator_info -> bool
val mk_fresh_void_exp_typ : unit -> Exp.t * Typ.t
val mk_fresh_void_id_typ : unit -> Ident.t * Typ.t
val mk_fresh_void_return : unit -> (Ident.t * Typ.t) * (Exp.t * Typ.t)
val last_or_mk_fresh_void_exp_typ : (Exp.t * Typ.t) list -> Exp.t * Typ.t
val should_remove_first_param : trans_state -> Clang_ast_t.stmt -> Typ.name option
(** Return a class name when the first parameter should be removed according to its context, for
example, when [self] or [\[x class\]] is given as the first parameter for a class method. *)