Refactor SymExec.Builtin into toplevel module

Summary:public
This will allow SymExec to depend on Inferconfig with introducing
circular dependencies, as Inferconfig calls Builtin.is_registered.

Reviewed By: jeremydubreil

Differential Revision: D3100614

fb-gh-sync-id: 786cf62
fbshipit-source-id: 786cf62
master
Josh Berdine 9 years ago committed by Facebook Github Bot 6
parent 6ae225dd62
commit 2dcd93204c

@ -0,0 +1,63 @@
(*
* Copyright (c) 2016 - 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.
*)
(** Module for builtin functions with their symbolic execution handler *)
type args = {
pdesc : Cfg.Procdesc.t;
instr : Sil.instr;
tenv : Sil.tenv;
prop_ : Prop.normal Prop.t;
path : Paths.Path.t;
ret_ids : Ident.t list;
args : (Sil.exp * Sil.typ) list;
proc_name : Procname.t;
loc : Location.t;
}
type ret_typ = (Prop.normal Prop.t * Paths.Path.t) list
type t = args -> ret_typ
(* builtin function names for which we do symbolic execution *)
let builtin_functions = Procname.Hash.create 4
(* Check if the function is a builtin *)
let is_registered name =
Procname.Hash.mem builtin_functions name
(* get the symbolic execution handler associated to the builtin function name *)
let get name : t =
try Procname.Hash.find builtin_functions name
with Not_found -> assert false
(* register a builtin function name and symbolic execution handler *)
let register proc_name_str (sym_exe_fun: t) =
let proc_name = Procname.from_string_c_fun proc_name_str in
Procname.Hash.replace builtin_functions proc_name sym_exe_fun;
proc_name
(* register a builtin [Procname.t] and symbolic execution handler *)
let register_procname proc_name (sym_exe_fun: t) =
Procname.Hash.replace builtin_functions proc_name sym_exe_fun
(** print the functions registered *)
let pp_registered fmt () =
let builtin_names = ref [] in
Procname.Hash.iter (fun name _ -> builtin_names := name :: !builtin_names) builtin_functions;
builtin_names := IList.sort Procname.compare !builtin_names;
let pp pname = Format.fprintf fmt "%a@\n" Procname.pp pname in
Format.fprintf fmt "Registered builtins:@\n @[";
IList.iter pp !builtin_names;
Format.fprintf fmt "@]@."
(** print the builtin functions and exit *)
let print_and_exit () =
pp_registered Format.std_formatter ();
exit 0

@ -0,0 +1,41 @@
(*
* Copyright (c) 2016 - 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.
*)
(** Module for builtin functions with their symbolic execution handler *)
type args = {
pdesc : Cfg.Procdesc.t;
instr : Sil.instr;
tenv : Sil.tenv;
prop_ : Prop.normal Prop.t;
path : Paths.Path.t;
ret_ids : Ident.t list;
args : (Sil.exp * Sil.typ) list;
proc_name : Procname.t;
loc : Location.t;
}
type ret_typ = (Prop.normal Prop.t * Paths.Path.t) list
type t = args -> ret_typ
val register : string -> t -> Procname.t
(** Register a builtin function name and symbolic execution handler *)
val register_procname : Procname.t -> t -> unit
(** Register a builtin [Procname.t] and symbolic execution handler *)
val is_registered : Procname.t -> bool
(** Check if the function is a builtin *)
val get : Procname.t -> t
(** Get the symbolic execution handler associated to the builtin function name *)
val print_and_exit : unit -> 'a
(** Print the builtin functions and exit *)

@ -73,7 +73,7 @@ let arg_desc =
"use file for the out channel" "use file for the out channel"
; ;
"-print_builtins", "-print_builtins",
Arg.Unit SymExec.print_builtins, Arg.Unit Builtin.print_and_exit,
None, None,
"print the builtin functions and exit" "print the builtin functions and exit"
; ;

@ -153,7 +153,7 @@ let load_patterns json_key inferconfig =
(** Check if a proc name is matching the name given as string. *) (** Check if a proc name is matching the name given as string. *)
let match_method language proc_name method_name = let match_method language proc_name method_name =
not (SymExec.function_is_builtin proc_name) && not (Builtin.is_registered proc_name) &&
Procname.get_language proc_name = language && Procname.get_language proc_name = language &&
Procname.get_method proc_name = method_name Procname.get_method proc_name = method_name

@ -248,67 +248,6 @@ let update_iter iter pi sigma =
let iter' = Prop.prop_iter_update_current_by_list iter sigma in let iter' = Prop.prop_iter_update_current_by_list iter sigma in
IList.fold_left (Prop.prop_iter_add_atom false) iter' pi IList.fold_left (Prop.prop_iter_add_atom false) iter' pi
(** Module for builtin functions with their symbolic execution handler *)
module Builtin = struct
type ret_typ = (Prop.normal Prop.t * Paths.Path.t) list
type builtin_args =
{
pdesc : Cfg.Procdesc.t;
instr : Sil.instr;
tenv : Sil.tenv;
prop_ : Prop.normal Prop.t;
path : Paths.Path.t;
ret_ids : Ident.t list;
args : (Sil.exp * Sil.typ) list;
proc_name : Procname.t;
loc : Location.t;
}
type sym_exe_builtin = builtin_args -> ret_typ
(* builtin function names for which we do symbolic execution *)
let builtin_functions = Procname.Hash.create 4
(* Check if the function is a builtin *)
let is_registered name =
Procname.Hash.mem builtin_functions name
(* get the symbolic execution handler associated to the builtin function name *)
let get_sym_exe_builtin name : sym_exe_builtin =
try Procname.Hash.find builtin_functions name
with Not_found -> assert false
(* register a builtin function name and symbolic execution handler *)
let register proc_name_str (sym_exe_fun: sym_exe_builtin) =
let proc_name = Procname.from_string_c_fun proc_name_str in
Procname.Hash.replace builtin_functions proc_name sym_exe_fun;
proc_name
(* register a builtin [Procname.t] and symbolic execution handler *)
let register_procname proc_name (sym_exe_fun: sym_exe_builtin) =
Procname.Hash.replace builtin_functions proc_name sym_exe_fun
(** print the functions registered *)
let pp_registered fmt () =
let builtin_names = ref [] in
Procname.Hash.iter (fun name _ -> builtin_names := name :: !builtin_names) builtin_functions;
builtin_names := IList.sort Procname.compare !builtin_names;
let pp pname = Format.fprintf fmt "%a@\n" Procname.pp pname in
Format.fprintf fmt "Registered builtins:@\n @[";
IList.iter pp !builtin_names;
Format.fprintf fmt "@]@."
end
(** print the builtin functions and exit *)
let print_builtins () =
Builtin.pp_registered Format.std_formatter ();
exit 0
(** Check if the function is a builtin *)
let function_is_builtin = Builtin.is_registered
(** Precondition: se should not include hpara_psto (** Precondition: se should not include hpara_psto
that could mean nonempty heaps. *) that could mean nonempty heaps. *)
let rec execute_nullify_se = function let rec execute_nullify_se = function
@ -1084,8 +1023,8 @@ let rec sym_exec tenv current_pdesc _instr (prop_: Prop.normal Prop.t) path
let n_cond, prop = exp_norm_check_arith current_pname prop__ cond in let n_cond, prop = exp_norm_check_arith current_pname prop__ cond in
ret_old_path (Propset.to_proplist (prune_prop n_cond prop)) ret_old_path (Propset.to_proplist (prune_prop n_cond prop))
| Sil.Call (ret_ids, Sil.Const (Sil.Cfun callee_pname), args, loc, _) | Sil.Call (ret_ids, Sil.Const (Sil.Cfun callee_pname), args, loc, _)
when function_is_builtin callee_pname -> when Builtin.is_registered callee_pname ->
let sym_exe_builtin = Builtin.get_sym_exe_builtin callee_pname in let sym_exe_builtin = Builtin.get callee_pname in
sym_exe_builtin sym_exe_builtin
{ {
pdesc = current_pdesc; pdesc = current_pdesc;

@ -13,12 +13,6 @@
(** Lookup Java types by name. *) (** Lookup Java types by name. *)
val lookup_java_typ_from_string : Sil.tenv -> string -> Sil.typ val lookup_java_typ_from_string : Sil.tenv -> string -> Sil.typ
(** print the builtin functions and exit *)
val print_builtins : unit -> unit
(** Check if the function is a builtin *)
val function_is_builtin : Procname.t -> bool
(** symbolic execution on the level of sets of propositions *) (** symbolic execution on the level of sets of propositions *)
val lifted_sym_exec : (exn -> unit) -> Sil.tenv -> Cfg.Procdesc.t -> val lifted_sym_exec : (exn -> unit) -> Sil.tenv -> Cfg.Procdesc.t ->
Paths.PathSet.t -> Cfg.Node.t -> Sil.instr list -> Paths.PathSet.t Paths.PathSet.t -> Cfg.Node.t -> Sil.instr list -> Paths.PathSet.t

@ -50,7 +50,7 @@ let node_throws node (proc_throws : Procname.t -> throws) : throws =
(* assignment to return variable is an artifact of a throw instruction *) (* assignment to return variable is an artifact of a throw instruction *)
Throws Throws
| Sil.Call (_, Sil.Const (Sil.Cfun callee_pn), _, _, _) | Sil.Call (_, Sil.Const (Sil.Cfun callee_pn), _, _, _)
when SymExec.function_is_builtin callee_pn -> when Builtin.is_registered callee_pn ->
if Procname.equal callee_pn SymExec.ModelBuiltins.__cast if Procname.equal callee_pn SymExec.ModelBuiltins.__cast
then DontKnow then DontKnow
else DoesNotThrow else DoesNotThrow

@ -31,7 +31,7 @@ let is_modeled_expensive =
Inferconfig.ModeledExpensiveMatcher.load_matcher config_file) in Inferconfig.ModeledExpensiveMatcher.load_matcher config_file) in
fun tenv proc_name -> match proc_name with fun tenv proc_name -> match proc_name with
| Procname.Java proc_name_java -> | Procname.Java proc_name_java ->
not (SymExec.function_is_builtin proc_name) && not (Builtin.is_registered proc_name) &&
let classname = let classname =
Typename.Java.from_string (Procname.java_get_class_name proc_name_java) in Typename.Java.from_string (Procname.java_get_class_name proc_name_java) in
(Lazy.force matcher) (AndroidFramework.is_subclass tenv classname) proc_name (Lazy.force matcher) (AndroidFramework.is_subclass tenv classname) proc_name
@ -123,7 +123,7 @@ let is_allocator tenv pname = match pname with
Typename.Java.from_string (Procname.java_get_class_name pname_java) in Typename.Java.from_string (Procname.java_get_class_name pname_java) in
AndroidFramework.is_throwable tenv class_name in AndroidFramework.is_throwable tenv class_name in
Procname.is_constructor pname Procname.is_constructor pname
&& not (SymExec.function_is_builtin pname) && not (Builtin.is_registered pname)
&& not (is_throwable ()) && not (is_throwable ())
| _ -> | _ ->
false false

@ -442,7 +442,7 @@ struct
!CFrontend_config.language = CFrontend_config.OBJCPP) then !CFrontend_config.language = CFrontend_config.OBJCPP) then
SymExec.ModelBuiltins.malloc_no_fail SymExec.ModelBuiltins.malloc_no_fail
else Procname.from_string_c_fun name in else Procname.from_string_c_fun name in
let is_builtin = SymExec.function_is_builtin non_mangled_func_name in let is_builtin = Builtin.is_registered non_mangled_func_name in
if is_builtin then (* malloc, free, exit, scanf, ... *) if is_builtin then (* malloc, free, exit, scanf, ... *)
{ empty_res_trans with exps = [(Sil.Const (Sil.Cfun non_mangled_func_name), typ)] } { empty_res_trans with exps = [(Sil.Const (Sil.Cfun non_mangled_func_name), typ)] }
else else
@ -849,7 +849,7 @@ struct
(match callee_pname_opt with (match callee_pname_opt with
| Some callee_pname -> | Some callee_pname ->
let open CContext in let open CContext in
if not (SymExec.function_is_builtin callee_pname) then if not (Builtin.is_registered callee_pname) then
begin begin
Cg.add_edge context.cg procname callee_pname; Cg.add_edge context.cg procname callee_pname;
end end

@ -73,7 +73,7 @@ module ComplexExpressions = struct
procname_optional_isPresent pn || procname_optional_isPresent pn ||
procname_instanceof pn || procname_instanceof pn ||
procname_containsKey pn || procname_containsKey pn ||
SymExec.function_is_builtin pn Builtin.is_registered pn
exception Not_handled exception Not_handled
@ -557,7 +557,7 @@ let typecheck_instr
[loc] [loc]
) )
typestate typestate
| Sil.Call (_, Sil.Const (Sil.Cfun pn), _, _, _) when SymExec.function_is_builtin pn -> | Sil.Call (_, Sil.Const (Sil.Cfun pn), _, _, _) when Builtin.is_registered pn ->
typestate (* skip othe builtins *) typestate (* skip othe builtins *)
| Sil.Call | Sil.Call
(ret_ids, (ret_ids,

@ -589,7 +589,7 @@ let method_invocation context loc pc var_opt cn ms sil_obj_opt expr_list invoke_
let callee_procname = let callee_procname =
let proc = Procname.from_string_c_fun (JBasics.ms_name ms) in let proc = Procname.from_string_c_fun (JBasics.ms_name ms) in
if JBasics.cn_equal cn' JConfig.infer_builtins_cl && if JBasics.cn_equal cn' JConfig.infer_builtins_cl &&
SymExec.function_is_builtin proc Builtin.is_registered proc
then proc then proc
else Procname.Java (JTransType.get_method_procname cn' ms method_kind) in else Procname.Java (JTransType.get_method_procname cn' ms method_kind) in
let call_idl, call_instrs = let call_idl, call_instrs =

Loading…
Cancel
Save