[inferbo] Use record environment type for model

Summary:
It abstracts the environments required in modeling functions and type
declarations as a record type.

Reviewed By: mbouaziz

Differential Revision: D7065996

fbshipit-source-id: b60cd3c
master
Sungkeun Cho 7 years ago committed by Facebook Github Bot
parent 3cb56ea3c1
commit 8dd45eebde

@ -73,8 +73,9 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| Typ.Tstruct typename -> ( | Typ.Tstruct typename -> (
match Models.TypName.dispatch typename with match Models.TypName.dispatch typename with
| Some {Models.declare_symbolic} -> | Some {Models.declare_symbolic} ->
declare_symbolic ~decl_sym_val pname tenv node location ~depth loc ~inst_num let model_env = Models.mk_model_env pname node location tenv in
~new_sym_num ~new_alloc_num mem declare_symbolic ~decl_sym_val model_env ~depth loc ~inst_num ~new_sym_num
~new_alloc_num mem
| None -> | None ->
let decl_fld mem (fn, typ, _) = let decl_fld mem (fn, typ, _) =
let loc_fld = Loc.append_field loc ~fn in let loc_fld = Loc.append_field loc ~fn in
@ -223,21 +224,23 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
mem mem
| Prune (exp, _, _, _) -> | Prune (exp, _, _, _) ->
Sem.prune exp mem Sem.prune exp mem
| Call (ret, Const Cfun callee_pname, params, location, _) -> ( | Call (ret, Const Cfun callee_pname, params, location, _)
match Models.Procname.dispatch callee_pname params with -> (
| Some {Models.exec} -> let model_env = Models.mk_model_env callee_pname node location tenv ?ret in
exec callee_pname ret node location mem match Models.Procname.dispatch callee_pname params with
| None -> | Some {Models.exec} ->
match Summary.read_summary pdesc callee_pname with exec model_env mem
| Some summary ->
let callee = extras callee_pname in
instantiate_mem tenv ret callee callee_pname params mem summary location
| None -> | None ->
L.(debug BufferOverrun Verbose) match Summary.read_summary pdesc callee_pname with
"/!\\ Unknown call to %a at %a@\n" Typ.Procname.pp callee_pname Location.pp | Some summary ->
location ; let callee = extras callee_pname in
Models.model_by_value Dom.Val.unknown callee_pname ret node location mem instantiate_mem tenv ret callee callee_pname params mem summary location
|> Dom.Mem.add_heap Loc.unknown Dom.Val.unknown ) | None ->
L.(debug BufferOverrun Verbose)
"/!\\ Unknown call to %a at %a@\n" Typ.Procname.pp callee_pname Location.pp
location ;
Models.model_by_value Dom.Val.unknown model_env mem
|> Dom.Mem.add_heap Loc.unknown Dom.Val.unknown )
| Declare_locals (locals, location) -> | Declare_locals (locals, location) ->
(* array allocation in stack e.g., int arr[10] *) (* array allocation in stack e.g., int arr[10] *)
let rec decl_local pname node location loc typ ~inst_num ~dimension mem = let rec decl_local pname node location loc typ ~inst_num ~dimension mem =
@ -249,7 +252,8 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| Typ.Tstruct typname -> ( | Typ.Tstruct typname -> (
match Models.TypName.dispatch typname with match Models.TypName.dispatch typname with
| Some {Models.declare_local} -> | Some {Models.declare_local} ->
declare_local ~decl_local pname node location loc ~inst_num ~dimension mem let model_env = Models.mk_model_env pname node location tenv in
declare_local ~decl_local model_env loc ~inst_num ~dimension mem
| None -> | None ->
(mem, inst_num) ) (mem, inst_num) )
| _ -> | _ ->
@ -390,7 +394,7 @@ module Report = struct
| Sil.Call (_, Const Cfun callee_pname, params, location, _) -> ( | Sil.Call (_, Const Cfun callee_pname, params, location, _) -> (
match Models.Procname.dispatch callee_pname params with match Models.Procname.dispatch callee_pname params with
| Some {Models.check} -> | Some {Models.check} ->
check pname node location mem cond_set check (Models.mk_model_env pname node location tenv) mem cond_set
| None -> | None ->
match Summary.read_summary pdesc callee_pname with match Summary.read_summary pdesc callee_pname with
| Some callee_summary -> | Some callee_summary ->

@ -20,28 +20,33 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
module CFG = BoUtils.CFG module CFG = BoUtils.CFG
module Sem = BoUtils.Sem module Sem = BoUtils.Sem
type exec_fun = type model_env =
Typ.Procname.t -> (Ident.t * Typ.t) option -> CFG.node -> Location.t -> Dom.Mem.astate { pname: Typ.Procname.t
-> Dom.Mem.astate ; node: CFG.node
; location: Location.t
; tenv: Tenv.t
; ret: (Ident.t * Typ.t) option }
let mk_model_env pname node location ?ret tenv = {pname; node; location; tenv; ret}
type check_fun = type exec_fun = model_env -> Dom.Mem.astate -> Dom.Mem.astate
Typ.Procname.t -> CFG.node -> Location.t -> Dom.Mem.astate -> PO.ConditionSet.t
-> PO.ConditionSet.t type check_fun = model_env -> Dom.Mem.astate -> PO.ConditionSet.t -> PO.ConditionSet.t
type model = {exec: exec_fun; check: check_fun} type model = {exec: exec_fun; check: check_fun}
type declare_local_fun = type declare_local_fun =
decl_local:BoUtils.Exec.decl_local -> Typ.Procname.t -> CFG.node -> Location.t -> Loc.t decl_local:BoUtils.Exec.decl_local -> model_env -> Loc.t -> inst_num:int -> dimension:int
-> inst_num:int -> dimension:int -> Dom.Mem.astate -> Dom.Mem.astate * int -> Dom.Mem.astate -> Dom.Mem.astate * int
type declare_symbolic_fun = type declare_symbolic_fun =
decl_sym_val:BoUtils.Exec.decl_sym_val -> Typ.Procname.t -> Tenv.t -> CFG.node -> Location.t decl_sym_val:BoUtils.Exec.decl_sym_val -> model_env -> depth:int -> Loc.t -> inst_num:int
-> depth:int -> Loc.t -> inst_num:int -> new_sym_num:BoUtils.counter -> new_sym_num:BoUtils.counter -> new_alloc_num:BoUtils.counter -> Dom.Mem.astate
-> new_alloc_num:BoUtils.counter -> Dom.Mem.astate -> Dom.Mem.astate -> Dom.Mem.astate
type typ_model = {declare_local: declare_local_fun; declare_symbolic: declare_symbolic_fun} type typ_model = {declare_local: declare_local_fun; declare_symbolic: declare_symbolic_fun}
let no_check _pname _node _location _mem cond_set = cond_set let no_check _model_env _mem cond_set = cond_set
(* NOTE: heuristic *) (* NOTE: heuristic *)
let get_malloc_info : Exp.t -> Typ.t * Int.t option * Exp.t = function let get_malloc_info : Exp.t -> Typ.t * Int.t option * Exp.t = function
@ -54,7 +59,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
(Typ.mk (Typ.Tint Typ.IChar), Some 1, x) (Typ.mk (Typ.Tint Typ.IChar), Some 1, x)
let check_alloc_size size_exp pname _node location mem cond_set = let check_alloc_size size_exp {pname; location} mem cond_set =
let _, _, length0 = get_malloc_info size_exp in let _, _, length0 = get_malloc_info size_exp in
let v_length = Sem.eval length0 mem in let v_length = Sem.eval length0 mem in
match Dom.Val.get_itv v_length with match Dom.Val.get_itv v_length with
@ -77,7 +82,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
let malloc size_exp = let malloc size_exp =
let exec pname ret node location mem = let exec {pname; ret; node; location} mem =
match ret with match ret with
| Some (id, _) -> | Some (id, _) ->
let typ, stride, length0 = get_malloc_info size_exp in let typ, stride, length0 = get_malloc_info size_exp in
@ -100,7 +105,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
let realloc = malloc let realloc = malloc
let inferbo_min e1 e2 = let inferbo_min e1 e2 =
let exec _pname ret _node _location mem = let exec {ret} mem =
match ret with match ret with
| Some (id, _) -> | Some (id, _) ->
let i1 = Sem.eval e1 mem |> Dom.Val.get_itv in let i1 = Sem.eval e1 mem |> Dom.Val.get_itv in
@ -114,7 +119,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
let inferbo_set_size e1 e2 = let inferbo_set_size e1 e2 =
let exec _pname _ret _node _location mem = let exec _model_env mem =
let locs = Sem.eval_locs e1 mem |> Dom.Val.get_pow_loc in let locs = Sem.eval_locs e1 mem |> Dom.Val.get_pow_loc in
let size = Sem.eval e2 mem |> Dom.Val.get_itv in let size = Sem.eval e2 mem |> Dom.Val.get_itv in
let arr = Dom.Mem.find_heap_set locs mem in let arr = Dom.Mem.find_heap_set locs mem in
@ -124,7 +129,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
{exec; check} {exec; check}
let model_by_value value _pname ret _node _location mem = let model_by_value value {ret} mem =
match ret with match ret with
| Some (id, _) -> | Some (id, _) ->
Dom.Mem.add_stack (Loc.of_id id) value mem Dom.Mem.add_stack (Loc.of_id id) value mem
@ -137,12 +142,12 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
let by_value value = {exec= model_by_value value; check= no_check} let by_value value = {exec= model_by_value value; check= no_check}
let bottom = let bottom =
let exec _pname _ret _node _location _mem = Bottom in let exec _model_env _mem = Bottom in
{exec; check= no_check} {exec; check= no_check}
let infer_print e = let infer_print e =
let exec _pname _ret _node location mem = let exec {location} mem =
L.(debug BufferOverrun Medium) L.(debug BufferOverrun Medium)
"@[<v>=== Infer Print === at %a@,%a@]%!" Location.pp location Dom.Val.pp (Sem.eval e mem) ; "@[<v>=== Infer Print === at %a@,%a@]%!" Location.pp location Dom.Val.pp (Sem.eval e mem) ;
mem mem
@ -151,7 +156,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
let set_array_length array length_exp = let set_array_length array length_exp =
let exec pname _ret node _location mem = let exec {pname; node} mem =
match array with match array with
| Exp.Lvar array_pvar, {Typ.desc= Typ.Tarray (typ, _, stride0)} -> | Exp.Lvar array_pvar, {Typ.desc= Typ.Tarray (typ, _, stride0)} ->
let length = Sem.eval length_exp mem |> Dom.Val.get_itv in let length = Sem.eval length_exp mem |> Dom.Val.get_itv in
@ -181,7 +186,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
module Boost = struct module Boost = struct
module Split = struct module Split = struct
let std_vector vector_arg = let std_vector vector_arg =
let exec _pname _ret _node location mem = let exec {location} mem =
Split.std_vector ~adds_at_least_one:true vector_arg location mem Split.std_vector ~adds_at_least_one:true vector_arg location mem
in in
{exec; check= no_check} {exec; check= no_check}
@ -191,7 +196,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
module Folly = struct module Folly = struct
module Split = struct module Split = struct
let std_vector vector_arg ignore_empty_opt = let std_vector vector_arg ignore_empty_opt =
let exec _pname _ret _node location mem = let exec {location} mem =
let adds_at_least_one = let adds_at_least_one =
match ignore_empty_opt with match ignore_empty_opt with
| Some ignore_empty_exp -> | Some ignore_empty_exp ->
@ -208,14 +213,14 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
module StdArray = struct module StdArray = struct
let typ typ length = let typ typ length =
let declare_local ~decl_local pname node location loc ~inst_num ~dimension mem = let declare_local ~decl_local {pname; node; location} loc ~inst_num ~dimension mem =
(* should this be deferred to the constructor? *) (* should this be deferred to the constructor? *)
let length = Some (IntLit.of_int64 length) in let length = Some (IntLit.of_int64 length) in
BoUtils.Exec.decl_local_array ~decl_local pname node location loc typ ~length ~inst_num BoUtils.Exec.decl_local_array ~decl_local pname node location loc typ ~length ~inst_num
~dimension mem ~dimension mem
in in
let declare_symbolic ~decl_sym_val pname tenv node location ~depth loc ~inst_num ~new_sym_num let declare_symbolic ~decl_sym_val {pname; tenv; node; location} ~depth loc ~inst_num
~new_alloc_num mem = ~new_sym_num ~new_alloc_num mem =
let offset = Itv.zero in let offset = Itv.zero in
let size = Itv.of_int64 length in let size = Itv.of_int64 length in
BoUtils.Exec.decl_sym_arr ~decl_sym_val pname tenv node location ~depth loc typ ~offset BoUtils.Exec.decl_sym_arr ~decl_sym_val pname tenv node location ~depth loc typ ~offset
@ -225,27 +230,27 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
let constructor _size = let constructor _size =
let exec _pname _ret _node _location mem = mem (* initialize? *) in let exec _model_env mem = mem (* initialize? *) in
{exec; check= no_check} {exec; check= no_check}
let at _size (array_exp, _) (index_exp, _) = let at _size (array_exp, _) (index_exp, _) =
(* TODO? use size *) (* TODO? use size *)
let exec _pname ret _node _location mem = let exec {ret} mem =
L.(debug BufferOverrun Verbose) "Using model std::array<_, %Ld>::at" _size ; L.(debug BufferOverrun Verbose) "Using model std::array<_, %Ld>::at" _size ;
match ret with match ret with
| Some (id, _) -> | Some (id, _) ->
BoUtils.Exec.load_val id (Sem.eval_lindex array_exp index_exp mem) mem BoUtils.Exec.load_val id (Sem.eval_lindex array_exp index_exp mem) mem
| None -> | None ->
mem mem
and check pname _node location mem cond_set = and check {pname; location} mem cond_set =
BoUtils.Check.lindex ~array_exp ~index_exp mem pname location cond_set BoUtils.Check.lindex ~array_exp ~index_exp mem pname location cond_set
in in
{exec; check} {exec; check}
let no_model = let no_model =
let exec pname _ret _node location mem = let exec {pname; location} mem =
L.(debug BufferOverrun Verbose) L.(debug BufferOverrun Verbose)
"No model for %a at %a" Typ.Procname.pp pname Location.pp location ; "No model for %a at %a" Typ.Procname.pp pname Location.pp location ;
mem mem
@ -259,10 +264,10 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
"No %s type model in %a at %a" kind Typ.Procname.pp pname Location.pp location ; "No %s type model in %a at %a" kind Typ.Procname.pp pname Location.pp location ;
mem mem
in in
let declare_local ~decl_local:_ pname _node location _loc ~inst_num ~dimension:_ mem = let declare_local ~decl_local:_ {pname; location} _loc ~inst_num ~dimension:_ mem =
(no_model "local" pname location mem, inst_num) (no_model "local" pname location mem, inst_num)
in in
let declare_symbolic ~decl_sym_val:_ pname _tenv _node location ~depth:_ _loc ~inst_num:_ let declare_symbolic ~decl_sym_val:_ {pname; location} ~depth:_ _loc ~inst_num:_
~new_sym_num:_ ~new_alloc_num:_ mem = ~new_sym_num:_ ~new_alloc_num:_ mem =
no_model "symbolic" pname location mem no_model "symbolic" pname location mem
in in

Loading…
Cancel
Save