[Inferbo] Refactoring 7/8: remove dependency on CFG

Reviewed By: jvillard

Differential Revision: D7397133

fbshipit-source-id: e036c04
master
Mehdi Bouaziz 7 years ago committed by Facebook Github Bot
parent 722a66d452
commit a4eac6c2d6

@ -13,8 +13,11 @@
open! IStd open! IStd
open AbsLoc open AbsLoc
open! AbstractDomain.Types open! AbstractDomain.Types
module L = Logging module BoUtils = BufferOverrunUtils
module Dom = BufferOverrunDomain module Dom = BufferOverrunDomain
module L = Logging
module Models = BufferOverrunModels
module Sem = BufferOverrunSemantics
module Trace = BufferOverrunTrace module Trace = BufferOverrunTrace
module TraceSet = Trace.Set module TraceSet = Trace.Set
@ -31,9 +34,6 @@ end)
module TransferFunctions (CFG : ProcCfg.S) = struct module TransferFunctions (CFG : ProcCfg.S) = struct
module CFG = CFG module CFG = CFG
module Domain = Dom.Mem module Domain = Dom.Mem
module BoUtils = BufferOverrunUtils.Make (CFG)
module Sem = BoUtils.Sem
module Models = BufferOverrunModels.Make (BoUtils)
type extras = Typ.Procname.t -> Procdesc.t option type extras = Typ.Procname.t -> Procdesc.t option
@ -313,11 +313,6 @@ module CFG = Analyzer.TransferFunctions.CFG
type invariant_map = Analyzer.invariant_map type invariant_map = Analyzer.invariant_map
module Report = struct module Report = struct
(* I'd like to avoid rebuilding this :(
Everything depend on CFG only because of `get_allocsite` *)
module BoUtils = BufferOverrunUtils.Make (CFG)
module Sem = BoUtils.Sem
module Models = BufferOverrunModels.Make (BoUtils)
module PO = BufferOverrunProofObligations module PO = BufferOverrunProofObligations
type extras = Typ.Procname.t -> Procdesc.t option type extras = Typ.Procname.t -> Procdesc.t option

@ -11,48 +11,46 @@ open! IStd
open AbsLoc open AbsLoc
open! AbstractDomain.Types open! AbstractDomain.Types
module L = Logging module L = Logging
module BoUtils = BufferOverrunUtils
module Dom = BufferOverrunDomain module Dom = BufferOverrunDomain
module PO = BufferOverrunProofObligations module PO = BufferOverrunProofObligations
module Sem = BufferOverrunSemantics
module Trace = BufferOverrunTrace module Trace = BufferOverrunTrace
module TraceSet = Trace.Set module TraceSet = Trace.Set
module Make (BoUtils : BufferOverrunUtils.S) = struct type model_env =
module CFG = BoUtils.CFG
module Sem = BoUtils.Sem
type model_env =
{ pname: Typ.Procname.t { pname: Typ.Procname.t
; node_hash: int ; node_hash: int
; location: Location.t ; location: Location.t
; tenv: Tenv.t ; tenv: Tenv.t
; ret: (Ident.t * Typ.t) option } ; ret: (Ident.t * Typ.t) option }
let mk_model_env pname node_hash location ?ret tenv = {pname; node_hash; location; tenv; ret} let mk_model_env pname node_hash location ?ret tenv = {pname; node_hash; location; tenv; ret}
type exec_fun = model_env -> Dom.Mem.astate -> Dom.Mem.astate type exec_fun = model_env -> Dom.Mem.astate -> Dom.Mem.astate
type check_fun = model_env -> 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 -> model_env -> Loc.t -> inst_num:int -> dimension:int decl_local:BoUtils.Exec.decl_local -> model_env -> Loc.t -> 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 -> model_env -> depth:int -> Loc.t -> inst_num:int decl_sym_val:BoUtils.Exec.decl_sym_val -> model_env -> depth:int -> Loc.t -> inst_num:int
-> new_sym_num:Itv.Counter.t -> new_alloc_num:Itv.Counter.t -> Dom.Mem.astate -> Dom.Mem.astate -> new_sym_num:Itv.Counter.t -> new_alloc_num:Itv.Counter.t -> 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 _model_env _mem cond_set = cond_set let no_check _model_env _mem cond_set = cond_set
(* It returns a tuple of: (* It returns a tuple of:
- type of array element - type of array element
- stride of the type - stride of the type
- array size - array size
- flexible array size *) - flexible array size *)
let get_malloc_info : Exp.t -> Typ.t * Int.t option * Exp.t * Exp.t option = function let get_malloc_info : Exp.t -> Typ.t * Int.t option * Exp.t * Exp.t option = function
| Exp.BinOp (Binop.Mult, Exp.Sizeof {typ; nbytes}, length) | Exp.BinOp (Binop.Mult, Exp.Sizeof {typ; nbytes}, length)
| Exp.BinOp (Binop.Mult, length, Exp.Sizeof {typ; nbytes}) -> | Exp.BinOp (Binop.Mult, length, Exp.Sizeof {typ; nbytes}) ->
(typ, nbytes, length, None) (typ, nbytes, length, None)
@ -62,7 +60,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
(Typ.mk (Typ.Tint Typ.IChar), Some 1, x, None) (Typ.mk (Typ.Tint Typ.IChar), Some 1, x, None)
let check_alloc_size size_exp {pname; 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
@ -73,7 +71,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
PO.ConditionSet.add_alloc_size pname location ~length traces cond_set PO.ConditionSet.add_alloc_size pname location ~length traces cond_set
let set_uninitialized location (typ: Typ.t) ploc mem = let set_uninitialized location (typ: Typ.t) ploc mem =
match typ.desc with match typ.desc with
| Tint _ | Tfloat _ -> | Tint _ | Tfloat _ ->
Dom.Mem.weak_update_heap ploc Dom.Val.Itv.top mem Dom.Mem.weak_update_heap ploc Dom.Val.Itv.top mem
@ -84,7 +82,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
mem mem
let malloc size_exp = let malloc size_exp =
let exec {pname; ret; node_hash; location; tenv} mem = let exec {pname; ret; node_hash; location; tenv} mem =
match ret with match ret with
| Some (id, _) -> | Some (id, _) ->
@ -109,7 +107,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
{exec; check} {exec; check}
let realloc src_exp size_exp = let realloc src_exp size_exp =
let exec {ret; location; tenv} mem = let exec {ret; location; tenv} mem =
match ret with match ret with
| Some (id, _) -> | Some (id, _) ->
@ -131,7 +129,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
{exec; check} {exec; check}
let placement_new allocated_mem_exp = let placement_new allocated_mem_exp =
let exec {ret} mem = let exec {ret} mem =
match ret with match ret with
| Some (id, _) -> | Some (id, _) ->
@ -143,7 +141,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
{exec; check= no_check} {exec; check= no_check}
let inferbo_min e1 e2 = let inferbo_min e1 e2 =
let exec {ret} mem = let exec {ret} mem =
match ret with match ret with
| Some (id, _) -> | Some (id, _) ->
@ -157,7 +155,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
{exec; check= no_check} {exec; check= no_check}
let inferbo_set_size e1 e2 = let inferbo_set_size e1 e2 =
let exec _model_env 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
@ -168,7 +166,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
{exec; check} {exec; check}
let model_by_value value ret 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
@ -178,17 +176,17 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
mem mem
let by_value value = let by_value =
let exec {ret} mem = model_by_value value ret mem in let exec ~value {ret} mem = model_by_value value ret mem in
{exec; check= no_check} fun value -> {exec= exec ~value; check= no_check}
let bottom = let bottom =
let exec _model_env _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 {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) ;
@ -197,7 +195,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
{exec; check= no_check} {exec; check= no_check}
let set_array_length array length_exp = let set_array_length array length_exp =
let exec {pname; node_hash; location} mem = let exec {pname; node_hash; location} mem =
match array with match array with
| Exp.Lvar array_pvar, {Typ.desc= Typ.Tarray {elt; stride}} -> | Exp.Lvar array_pvar, {Typ.desc= Typ.Tarray {elt; stride}} ->
@ -215,7 +213,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
{exec; check} {exec; check}
module Split = struct module Split = struct
let std_vector ~adds_at_least_one (vector_exp, vector_typ) location mem = let std_vector ~adds_at_least_one (vector_exp, vector_typ) location mem =
let traces = BufferOverrunTrace.(Call location |> singleton |> Set.singleton) in let traces = BufferOverrunTrace.(Call location |> singleton |> Set.singleton) in
let increment_itv = if adds_at_least_one then Itv.pos else Itv.nat in let increment_itv = if adds_at_least_one then Itv.pos else Itv.nat in
@ -226,19 +224,17 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
Sem.eval vector_exp mem |> Dom.Val.get_all_locs |> PowLoc.append_field ~fn:size_field Sem.eval vector_exp mem |> Dom.Val.get_all_locs |> PowLoc.append_field ~fn:size_field
in in
Dom.Mem.transform_mem ~f:(Dom.Val.plus increment) vector_size_locs mem Dom.Mem.transform_mem ~f:(Dom.Val.plus increment) vector_size_locs mem
end end
module Boost = struct module Boost = struct
module Split = struct module Split = struct
let std_vector vector_arg = let std_vector vector_arg =
let exec {location} mem = let exec {location} mem = Split.std_vector ~adds_at_least_one:true vector_arg location mem in
Split.std_vector ~adds_at_least_one:true vector_arg location mem
in
{exec; check= no_check} {exec; check= no_check}
end end
end end
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 {location} mem = let exec {location} mem =
@ -254,22 +250,22 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
in in
{exec; check= no_check} {exec; check= no_check}
end end
end end
module StdArray = struct module StdArray = struct
let typ typ length = let typ typ length =
let declare_local ~decl_local {pname; node_hash; location} loc ~inst_num ~dimension mem = let declare_local ~decl_local {pname; node_hash; 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_hash location loc typ ~length BoUtils.Exec.decl_local_array ~decl_local pname ~node_hash location loc typ ~length ~inst_num
~inst_num ~dimension mem ~dimension mem
in in
let declare_symbolic ~decl_sym_val {pname; tenv; node_hash; location} ~depth loc ~inst_num let declare_symbolic ~decl_sym_val {pname; tenv; node_hash; location} ~depth loc ~inst_num
~new_sym_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_hash location ~depth loc typ BoUtils.Exec.decl_sym_arr ~decl_sym_val pname tenv ~node_hash location ~depth loc typ ~offset
~offset ~size ~inst_num ~new_sym_num ~new_alloc_num mem ~size ~inst_num ~new_sym_num ~new_alloc_num mem
in in
{declare_local; declare_symbolic} {declare_local; declare_symbolic}
@ -312,14 +308,14 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
let declare_local ~decl_local:_ {pname; 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; location} ~depth:_ _loc ~inst_num:_ let declare_symbolic ~decl_sym_val:_ {pname; location} ~depth:_ _loc ~inst_num:_ ~new_sym_num:_
~new_sym_num:_ ~new_alloc_num:_ mem = ~new_alloc_num:_ mem =
no_model "symbolic" pname location mem no_model "symbolic" pname location mem
in in
{declare_local; declare_symbolic} {declare_local; declare_symbolic}
end end
module Call = struct module Call = struct
let dispatch : model ProcnameDispatcher.Call.dispatcher = let dispatch : model ProcnameDispatcher.Call.dispatcher =
let open ProcnameDispatcher.Call in let open ProcnameDispatcher.Call in
let mk_std_array () = -"std" &:: "array" < any_typ &+ capt_int in let mk_std_array () = -"std" &:: "array" < any_typ &+ capt_int in
@ -347,13 +343,12 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
; std_array2 >:: "at" $ capt_arg $+ capt_arg $!--> StdArray.at ; std_array2 >:: "at" $ capt_arg $+ capt_arg $!--> StdArray.at
; std_array2 >:: "operator[]" $ capt_arg $+ capt_arg $!--> StdArray.at ; std_array2 >:: "operator[]" $ capt_arg $+ capt_arg $!--> StdArray.at
; -"std" &:: "array" &::.*--> StdArray.no_model ] ; -"std" &:: "array" &::.*--> StdArray.no_model ]
end end
module TypName = struct module TypName = struct
let dispatch : typ_model ProcnameDispatcher.TypName.dispatcher = let dispatch : typ_model ProcnameDispatcher.TypName.dispatcher =
let open ProcnameDispatcher.TypName in let open ProcnameDispatcher.TypName in
make_dispatcher make_dispatcher
[ -"std" &:: "array" < capt_typ `T &+ capt_int >--> StdArray.typ [ -"std" &:: "array" < capt_typ `T &+ capt_int >--> StdArray.typ
; -"std" &:: "array" &::.*--> StdArray.no_typ_model ] ; -"std" &:: "array" &::.*--> StdArray.no_typ_model ]
end
end end

@ -19,10 +19,7 @@ module Trace = BufferOverrunTrace
module TraceSet = Trace.Set module TraceSet = Trace.Set
open BufferOverrunDomain open BufferOverrunDomain
module Make (CFG : ProcCfg.S) = struct let eval_const : Const.t -> Val.t = function
exception Not_implemented
let eval_const : Const.t -> Val.t = function
| Const.Cint intlit -> ( | Const.Cint intlit -> (
try Val.of_int (IntLit.to_int intlit) with _ -> Val.Itv.top ) try Val.of_int (IntLit.to_int intlit) with _ -> Val.Itv.top )
| Const.Cfloat f -> | Const.Cfloat f ->
@ -31,9 +28,9 @@ module Make (CFG : ProcCfg.S) = struct
Val.Itv.top Val.Itv.top
(* TODO *) (* TODO *)
let sizeof_ikind : Typ.ikind -> int = function let sizeof_ikind : Typ.ikind -> int = function
| Typ.IChar | Typ.ISChar | Typ.IUChar | Typ.IBool -> | Typ.IChar | Typ.ISChar | Typ.IUChar | Typ.IBool ->
1 1
| Typ.IInt | Typ.IUInt -> | Typ.IInt | Typ.IUInt ->
@ -48,15 +45,15 @@ module Make (CFG : ProcCfg.S) = struct
16 16
let sizeof_fkind : Typ.fkind -> int = function let sizeof_fkind : Typ.fkind -> int = function
| Typ.FFloat -> | Typ.FFloat ->
4 4
| Typ.FDouble | Typ.FLongDouble -> | Typ.FDouble | Typ.FLongDouble ->
8 8
(* NOTE: assume 32bit machine *) (* NOTE: assume 32bit machine *)
let rec sizeof (typ: Typ.t) : int = let rec sizeof (typ: Typ.t) : int =
match typ.desc with match typ.desc with
| Typ.Tint ikind -> | Typ.Tint ikind ->
sizeof_ikind ikind sizeof_ikind ikind
@ -76,7 +73,7 @@ module Make (CFG : ProcCfg.S) = struct
4 4
let rec must_alias : Exp.t -> Exp.t -> Mem.astate -> bool = let rec must_alias : Exp.t -> Exp.t -> Mem.astate -> bool =
fun e1 e2 m -> fun e1 e2 m ->
match (e1, e2) with match (e1, e2) with
| Exp.Var x1, Exp.Var x2 -> ( | Exp.Var x1, Exp.Var x2 -> (
@ -111,7 +108,7 @@ module Make (CFG : ProcCfg.S) = struct
false false
and must_alias_opt : Exp.t option -> Exp.t option -> Mem.astate -> bool = and must_alias_opt : Exp.t option -> Exp.t option -> Mem.astate -> bool =
fun e1_opt e2_opt m -> fun e1_opt e2_opt m ->
match (e1_opt, e2_opt) with match (e1_opt, e2_opt) with
| Some e1, Some e2 -> | Some e1, Some e2 ->
@ -122,7 +119,7 @@ module Make (CFG : ProcCfg.S) = struct
false false
let comp_rev : Binop.t -> Binop.t = function let comp_rev : Binop.t -> Binop.t = function
| Binop.Lt -> | Binop.Lt ->
Binop.Gt Binop.Gt
| Binop.Gt -> | Binop.Gt ->
@ -139,7 +136,7 @@ module Make (CFG : ProcCfg.S) = struct
assert false assert false
let comp_not : Binop.t -> Binop.t = function let comp_not : Binop.t -> Binop.t = function
| Binop.Lt -> | Binop.Lt ->
Binop.Ge Binop.Ge
| Binop.Gt -> | Binop.Gt ->
@ -156,7 +153,7 @@ module Make (CFG : ProcCfg.S) = struct
assert false assert false
let rec must_alias_cmp : Exp.t -> Mem.astate -> bool = let rec must_alias_cmp : Exp.t -> Mem.astate -> bool =
fun e m -> fun e m ->
match e with match e with
| Exp.BinOp (Binop.Lt, e1, e2) | Exp.BinOp (Binop.Gt, e1, e2) | Exp.BinOp (Binop.Ne, e1, e2) -> | Exp.BinOp (Binop.Lt, e1, e2) | Exp.BinOp (Binop.Gt, e1, e2) | Exp.BinOp (Binop.Ne, e1, e2) ->
@ -186,7 +183,7 @@ module Make (CFG : ProcCfg.S) = struct
false false
let rec eval : Exp.t -> Mem.astate -> Val.t = let rec eval : Exp.t -> Mem.astate -> Val.t =
fun exp mem -> fun exp mem ->
if must_alias_cmp exp mem then Val.of_int 0 if must_alias_cmp exp mem then Val.of_int 0
else else
@ -217,8 +214,8 @@ module Make (CFG : ProcCfg.S) = struct
Val.Itv.top Val.Itv.top
(* NOTE: multidimensional array is not supported yet *) (* NOTE: multidimensional array is not supported yet *)
and eval_lindex array_exp index_exp mem = and eval_lindex array_exp index_exp mem =
let array_v, index_v = (eval array_exp mem, eval index_exp mem) in let array_v, index_v = (eval array_exp mem, eval index_exp mem) in
let arr = Val.plus_pi array_v index_v in let arr = Val.plus_pi array_v index_v in
if ArrayBlk.is_bot (Val.get_array_blk arr) then if ArrayBlk.is_bot (Val.get_array_blk arr) then
@ -236,7 +233,7 @@ module Make (CFG : ProcCfg.S) = struct
else arr else arr
and eval_unop : Unop.t -> Exp.t -> Mem.astate -> Val.t = and eval_unop : Unop.t -> Exp.t -> Mem.astate -> Val.t =
fun unop e mem -> fun unop e mem ->
let v = eval e mem in let v = eval e mem in
match unop with match unop with
@ -248,7 +245,7 @@ module Make (CFG : ProcCfg.S) = struct
Val.lnot v Val.lnot v
and eval_binop : Binop.t -> Exp.t -> Exp.t -> Mem.astate -> Val.t = and eval_binop : Binop.t -> Exp.t -> Exp.t -> Mem.astate -> Val.t =
fun binop e1 e2 mem -> fun binop e1 e2 mem ->
let v1 = eval e1 mem in let v1 = eval e1 mem in
let v2 = eval e2 mem in let v2 = eval e2 mem in
@ -293,7 +290,7 @@ module Make (CFG : ProcCfg.S) = struct
Val.lor_sem v1 v2 Val.lor_sem v1 v2
let rec eval_locs : Exp.t -> Mem.astate -> Val.t = let rec eval_locs : Exp.t -> Mem.astate -> Val.t =
fun exp mem -> fun exp mem ->
match exp with match exp with
| Exp.Var id -> ( | Exp.Var id -> (
@ -318,7 +315,7 @@ module Make (CFG : ProcCfg.S) = struct
Val.bot Val.bot
let get_allocsite : Typ.Procname.t -> node_hash:int -> inst_num:int -> dimension:int -> string = let get_allocsite : Typ.Procname.t -> node_hash:int -> inst_num:int -> dimension:int -> string =
fun proc_name ~node_hash ~inst_num ~dimension -> fun proc_name ~node_hash ~inst_num ~dimension ->
let proc_name = Typ.Procname.to_string proc_name in let proc_name = Typ.Procname.to_string proc_name in
let node_num = string_of_int node_hash in let node_num = string_of_int node_hash in
@ -327,7 +324,7 @@ module Make (CFG : ProcCfg.S) = struct
proc_name ^ "-" ^ node_num ^ "-" ^ inst_num ^ "-" ^ dimension |> Allocsite.make proc_name ^ "-" ^ node_num ^ "-" ^ inst_num ^ "-" ^ dimension |> Allocsite.make
let eval_array_alloc let eval_array_alloc
: Typ.Procname.t -> node_hash:int -> Typ.t -> stride:int option -> offset:Itv.t -> size:Itv.t : Typ.Procname.t -> node_hash:int -> Typ.t -> stride:int option -> offset:Itv.t -> size:Itv.t
-> inst_num:int -> dimension:int -> Val.t = -> inst_num:int -> dimension:int -> Val.t =
fun pdesc ~node_hash typ ~stride ~offset ~size ~inst_num ~dimension -> fun pdesc ~node_hash typ ~stride ~offset ~size ~inst_num ~dimension ->
@ -337,7 +334,7 @@ module Make (CFG : ProcCfg.S) = struct
ArrayBlk.make allocsite ~offset ~size ~stride |> Val.of_array_blk ArrayBlk.make allocsite ~offset ~size ~stride |> Val.of_array_blk
let prune_unop : PrunePairs.t ref -> Exp.t -> Mem.astate -> Mem.astate = let prune_unop : PrunePairs.t ref -> Exp.t -> Mem.astate -> Mem.astate =
fun prune_pairs e mem -> fun prune_pairs e mem ->
match e with match e with
| Exp.Var x -> ( | Exp.Var x -> (
@ -371,7 +368,7 @@ module Make (CFG : ProcCfg.S) = struct
mem mem
let prune_binop_left : PrunePairs.t ref -> Exp.t -> Mem.astate -> Mem.astate = let prune_binop_left : PrunePairs.t ref -> Exp.t -> Mem.astate -> Mem.astate =
fun prune_pairs e mem -> fun prune_pairs e mem ->
match e with match e with
| Exp.BinOp ((Binop.Lt as comp), Exp.Var x, e') | Exp.BinOp ((Binop.Lt as comp), Exp.Var x, e')
@ -405,7 +402,7 @@ module Make (CFG : ProcCfg.S) = struct
mem mem
let prune_binop_right : PrunePairs.t ref -> Exp.t -> Mem.astate -> Mem.astate = let prune_binop_right : PrunePairs.t ref -> Exp.t -> Mem.astate -> Mem.astate =
fun prune_pairs e mem -> fun prune_pairs e mem ->
match e with match e with
| Exp.BinOp ((Binop.Lt as c), e', Exp.Var x) | Exp.BinOp ((Binop.Lt as c), e', Exp.Var x)
@ -419,15 +416,15 @@ module Make (CFG : ProcCfg.S) = struct
mem mem
let is_unreachable_constant : Exp.t -> Mem.astate -> bool = let is_unreachable_constant : Exp.t -> Mem.astate -> bool =
fun e m -> Val.( <= ) ~lhs:(eval e m) ~rhs:(Val.of_int 0) fun e m -> Val.( <= ) ~lhs:(eval e m) ~rhs:(Val.of_int 0)
let prune_unreachable : Exp.t -> Mem.astate -> Mem.astate = let prune_unreachable : Exp.t -> Mem.astate -> Mem.astate =
fun e mem -> if is_unreachable_constant e mem then Mem.bot else mem fun e mem -> if is_unreachable_constant e mem then Mem.bot else mem
let prune : Exp.t -> Mem.astate -> Mem.astate = let prune : Exp.t -> Mem.astate -> Mem.astate =
fun e mem -> fun e mem ->
let prune_pairs = ref PrunePairs.empty in let prune_pairs = ref PrunePairs.empty in
let rec prune_helper e mem = let rec prune_helper e mem =
@ -462,13 +459,13 @@ module Make (CFG : ProcCfg.S) = struct
Mem.set_prune_pairs !prune_pairs mem Mem.set_prune_pairs !prune_pairs mem
let get_formals : Procdesc.t -> (Pvar.t * Typ.t) list = let get_formals : Procdesc.t -> (Pvar.t * Typ.t) list =
fun pdesc -> fun pdesc ->
let proc_name = Procdesc.get_proc_name pdesc in let proc_name = Procdesc.get_proc_name pdesc in
Procdesc.get_formals pdesc |> List.map ~f:(fun (name, typ) -> (Pvar.mk name proc_name, typ)) Procdesc.get_formals pdesc |> List.map ~f:(fun (name, typ) -> (Pvar.mk name proc_name, typ))
let get_matching_pairs let get_matching_pairs
: Tenv.t -> Val.t -> Val.t -> Typ.t -> Mem.astate -> Mem.astate : Tenv.t -> Val.t -> Val.t -> Typ.t -> Mem.astate -> Mem.astate
-> callee_ret_alias:AliasTarget.t option -> callee_ret_alias:AliasTarget.t option
-> (Itv.Bound.t * Itv.Bound.t bottom_lifted * TraceSet.t) list * AliasTarget.t option = -> (Itv.Bound.t * Itv.Bound.t bottom_lifted * TraceSet.t) list * AliasTarget.t option =
@ -535,7 +532,7 @@ module Make (CFG : ProcCfg.S) = struct
(pairs, !ret_alias) (pairs, !ret_alias)
let subst_map_of_pairs let subst_map_of_pairs
: (Itv.Bound.t * Itv.Bound.t bottom_lifted * TraceSet.t) list : (Itv.Bound.t * Itv.Bound.t bottom_lifted * TraceSet.t) list
-> Itv.Bound.t bottom_lifted Itv.SubstMap.t * TraceSet.t Itv.SubstMap.t = -> Itv.Bound.t bottom_lifted Itv.SubstMap.t * TraceSet.t Itv.SubstMap.t =
fun pairs -> fun pairs ->
@ -548,7 +545,7 @@ module Make (CFG : ProcCfg.S) = struct
List.fold ~f:add_pair ~init:(Itv.SubstMap.empty, Itv.SubstMap.empty) pairs List.fold ~f:add_pair ~init:(Itv.SubstMap.empty, Itv.SubstMap.empty) pairs
let rec list_fold2_def let rec list_fold2_def
: default:Val.t -> f:('a -> Val.t -> 'b -> 'b) -> 'a list -> Val.t list -> init:'b -> 'b = : default:Val.t -> f:('a -> Val.t -> 'b -> 'b) -> 'a list -> Val.t list -> init:'b -> 'b =
fun ~default ~f xs ys ~init:acc -> fun ~default ~f xs ys ~init:acc ->
match (xs, ys) with match (xs, ys) with
@ -562,7 +559,7 @@ module Make (CFG : ProcCfg.S) = struct
list_fold2_def ~default ~f xs' ys' ~init:(f x y acc) list_fold2_def ~default ~f xs' ys' ~init:(f x y acc)
let get_subst_map let get_subst_map
: Tenv.t -> Procdesc.t -> (Exp.t * 'a) list -> Mem.astate -> Mem.astate : Tenv.t -> Procdesc.t -> (Exp.t * 'a) list -> Mem.astate -> Mem.astate
-> callee_ret_alias:AliasTarget.t option -> callee_ret_alias:AliasTarget.t option
-> (Itv.Bound.t bottom_lifted Itv.SubstMap.t * TraceSet.t Itv.SubstMap.t) -> (Itv.Bound.t bottom_lifted Itv.SubstMap.t * TraceSet.t Itv.SubstMap.t)
@ -581,4 +578,3 @@ module Make (CFG : ProcCfg.S) = struct
list_fold2_def ~default:Val.Itv.top ~f:add_pair formals actuals ~init:([], None) list_fold2_def ~default:Val.Itv.top ~f:add_pair formals actuals ~init:([], None)
in in
(subst_map_of_pairs pairs, ret_alias) (subst_map_of_pairs pairs, ret_alias)
end

@ -13,55 +13,11 @@ open! AbstractDomain.Types
module L = Logging module L = Logging
module Dom = BufferOverrunDomain module Dom = BufferOverrunDomain
module PO = BufferOverrunProofObligations module PO = BufferOverrunProofObligations
module Sem = BufferOverrunSemantics
module Trace = BufferOverrunTrace module Trace = BufferOverrunTrace
module TraceSet = Trace.Set module TraceSet = Trace.Set
module type S = sig module Exec = struct
module CFG : ProcCfg.S
module Sem : module type of BufferOverrunSemantics.Make (CFG)
module Exec : sig
val load_val : Ident.t -> Dom.Val.astate -> Dom.Mem.astate -> Dom.Mem.astate
type decl_local =
Typ.Procname.t -> node_hash:int -> Location.t -> Loc.t -> Typ.t -> inst_num:int
-> dimension:int -> Dom.Mem.astate -> Dom.Mem.astate * int
val decl_local_array :
decl_local:decl_local -> Typ.Procname.t -> node_hash:int -> Location.t -> Loc.t -> Typ.t
-> length:IntLit.t option -> ?stride:int -> inst_num:int -> dimension:int -> Dom.Mem.astate
-> Dom.Mem.astate * int
type decl_sym_val =
Typ.Procname.t -> Tenv.t -> node_hash:int -> Location.t -> depth:int -> Loc.t -> Typ.t
-> Dom.Mem.astate -> Dom.Mem.astate
val decl_sym_arr :
decl_sym_val:decl_sym_val -> Typ.Procname.t -> Tenv.t -> node_hash:int -> Location.t
-> depth:int -> Loc.t -> Typ.t -> ?offset:Itv.t -> ?size:Itv.t -> inst_num:int
-> new_sym_num:Itv.Counter.t -> new_alloc_num:Itv.Counter.t -> Dom.Mem.astate
-> Dom.Mem.astate
val init_array_fields :
Tenv.t -> Typ.Procname.t -> node_hash:int -> Typ.t -> PowLoc.t -> ?dyn_length:Exp.t
-> Dom.Mem.astate -> Dom.Mem.astate
val set_dyn_length : Tenv.t -> Typ.t -> PowLoc.t -> Itv.t -> Dom.Mem.astate -> Dom.Mem.astate
end
module Check : sig
val lindex :
array_exp:Exp.t -> index_exp:Exp.t -> Dom.Mem.astate -> Typ.Procname.t -> Location.t
-> PO.ConditionSet.t -> PO.ConditionSet.t
end
end
module Make (CFG : ProcCfg.S) = struct
module CFG = CFG
module Sem = BufferOverrunSemantics.Make (CFG)
module Exec = struct
let load_val id val_ mem = let load_val id val_ mem =
let locs = val_ |> Dom.Val.get_all_locs in let locs = val_ |> Dom.Val.get_all_locs in
let v = Dom.Mem.find_heap_set locs mem in let v = Dom.Mem.find_heap_set locs mem in
@ -76,18 +32,16 @@ module Make (CFG : ProcCfg.S) = struct
let decl_local_array let decl_local_array
: decl_local:decl_local -> Typ.Procname.t -> node_hash:int -> Location.t -> Loc.t -> Typ.t : decl_local:decl_local -> Typ.Procname.t -> node_hash:int -> Location.t -> Loc.t -> Typ.t
-> length:IntLit.t option -> ?stride:int -> inst_num:int -> dimension:int -> length:IntLit.t option -> ?stride:int -> inst_num:int -> dimension:int -> Dom.Mem.astate
-> Dom.Mem.astate -> Dom.Mem.astate * int = -> Dom.Mem.astate * int =
fun ~decl_local pname ~node_hash location loc typ ~length ?stride ~inst_num ~dimension mem -> fun ~decl_local pname ~node_hash location loc typ ~length ?stride ~inst_num ~dimension mem ->
let size = Option.value_map ~default:Itv.top ~f:Itv.of_int_lit length in let size = Option.value_map ~default:Itv.top ~f:Itv.of_int_lit length in
let arr = let arr =
Sem.eval_array_alloc pname ~node_hash typ ~stride ~offset:Itv.zero ~size ~inst_num Sem.eval_array_alloc pname ~node_hash typ ~stride ~offset:Itv.zero ~size ~inst_num ~dimension
~dimension
|> Dom.Val.add_trace_elem (Trace.ArrDecl location) |> Dom.Val.add_trace_elem (Trace.ArrDecl location)
in in
let mem = let mem =
if Int.equal dimension 1 then Dom.Mem.add_stack loc arr mem if Int.equal dimension 1 then Dom.Mem.add_stack loc arr mem else Dom.Mem.add_heap loc arr mem
else Dom.Mem.add_heap loc arr mem
in in
let loc = Loc.of_allocsite (Sem.get_allocsite pname ~node_hash ~inst_num ~dimension) in let loc = Loc.of_allocsite (Sem.get_allocsite pname ~node_hash ~inst_num ~dimension) in
let mem, _ = let mem, _ =
@ -153,8 +107,7 @@ module Make (CFG : ProcCfg.S) = struct
match Tenv.lookup tenv typename with match Tenv.lookup tenv typename with
| Some str -> | Some str ->
let f = init_field locs (dimension + 1) in let f = init_field locs (dimension + 1) in
IList.fold_last ~f ~f_last:(f ?dyn_length) ~init:(mem, 1) str.Typ.Struct.fields IList.fold_last ~f ~f_last:(f ?dyn_length) ~init:(mem, 1) str.Typ.Struct.fields |> fst
|> fst
| None -> | None ->
mem ) mem )
| _ -> | _ ->
@ -182,9 +135,9 @@ module Make (CFG : ProcCfg.S) = struct
mem ) mem )
| _ -> | _ ->
mem mem
end end
module Check = struct module Check = struct
let array_access ~arr ~idx ~is_plus pname location cond_set = let array_access ~arr ~idx ~is_plus pname location cond_set =
let arr_blk = Dom.Val.get_array_blk arr in let arr_blk = Dom.Val.get_array_blk arr in
let arr_traces = Dom.Val.get_traces arr in let arr_traces = Dom.Val.get_traces arr in
@ -210,5 +163,4 @@ module Make (CFG : ProcCfg.S) = struct
let arr = Dom.Mem.find_set locs mem in let arr = Dom.Mem.find_set locs mem in
let idx = Sem.eval index_exp mem in let idx = Sem.eval index_exp mem in
array_access ~arr ~idx ~is_plus:true pname location cond_set array_access ~arr ~idx ~is_plus:true pname location cond_set
end
end end

@ -0,0 +1,51 @@
(*
* Copyright (c) 2017 - 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.
*)
open! IStd
open AbsLoc
module Dom = BufferOverrunDomain
module PO = BufferOverrunProofObligations
module Exec : sig
val load_val : Ident.t -> Dom.Val.astate -> Dom.Mem.astate -> Dom.Mem.astate
type decl_local =
Typ.Procname.t -> node_hash:int -> Location.t -> Loc.t -> Typ.t -> inst_num:int
-> dimension:int -> Dom.Mem.astate -> Dom.Mem.astate * int
val decl_local_array :
decl_local:decl_local -> Typ.Procname.t -> node_hash:int -> Location.t -> Loc.t -> Typ.t
-> length:IntLit.t option -> ?stride:int -> inst_num:int -> dimension:int -> Dom.Mem.astate
-> Dom.Mem.astate * int
type decl_sym_val =
Typ.Procname.t -> Tenv.t -> node_hash:int -> Location.t -> depth:int -> Loc.t -> Typ.t
-> Dom.Mem.astate -> Dom.Mem.astate
val decl_sym_arr :
decl_sym_val:decl_sym_val -> Typ.Procname.t -> Tenv.t -> node_hash:int -> Location.t
-> depth:int -> Loc.t -> Typ.t -> ?offset:Itv.t -> ?size:Itv.t -> inst_num:int
-> new_sym_num:Itv.Counter.t -> new_alloc_num:Itv.Counter.t -> Dom.Mem.astate -> Dom.Mem.astate
val init_array_fields :
Tenv.t -> Typ.Procname.t -> node_hash:int -> Typ.t -> PowLoc.t -> ?dyn_length:Exp.t
-> Dom.Mem.astate -> Dom.Mem.astate
val set_dyn_length : Tenv.t -> Typ.t -> PowLoc.t -> Itv.t -> Dom.Mem.astate -> Dom.Mem.astate
end
module Check : sig
val array_access :
arr:Dom.Val.t -> idx:Dom.Val.t -> is_plus:bool -> Typ.Procname.t -> Location.t
-> PO.ConditionSet.t -> PO.ConditionSet.t
val lindex :
array_exp:Exp.t -> index_exp:Exp.t -> Dom.Mem.astate -> Typ.Procname.t -> Location.t
-> PO.ConditionSet.t -> PO.ConditionSet.t
end
Loading…
Cancel
Save