|
|
|
@ -11,48 +11,46 @@ open! IStd
|
|
|
|
|
open AbsLoc
|
|
|
|
|
open! AbstractDomain.Types
|
|
|
|
|
module L = Logging
|
|
|
|
|
module BoUtils = BufferOverrunUtils
|
|
|
|
|
module Dom = BufferOverrunDomain
|
|
|
|
|
module PO = BufferOverrunProofObligations
|
|
|
|
|
module Sem = BufferOverrunSemantics
|
|
|
|
|
module Trace = BufferOverrunTrace
|
|
|
|
|
module TraceSet = Trace.Set
|
|
|
|
|
|
|
|
|
|
module Make (BoUtils : BufferOverrunUtils.S) = struct
|
|
|
|
|
module CFG = BoUtils.CFG
|
|
|
|
|
module Sem = BoUtils.Sem
|
|
|
|
|
|
|
|
|
|
type model_env =
|
|
|
|
|
type model_env =
|
|
|
|
|
{ pname: Typ.Procname.t
|
|
|
|
|
; node_hash: int
|
|
|
|
|
; location: Location.t
|
|
|
|
|
; tenv: Tenv.t
|
|
|
|
|
; 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
|
|
|
|
|
-> 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
|
|
|
|
|
-> 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
|
|
|
|
|
- stride of the type
|
|
|
|
|
- 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, length, Exp.Sizeof {typ; nbytes}) ->
|
|
|
|
|
(typ, nbytes, length, None)
|
|
|
|
@ -62,7 +60,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
|
|
|
|
|
(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 v_length = Sem.eval length0 mem in
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let set_uninitialized location (typ: Typ.t) ploc mem =
|
|
|
|
|
let set_uninitialized location (typ: Typ.t) ploc mem =
|
|
|
|
|
match typ.desc with
|
|
|
|
|
| Tint _ | Tfloat _ ->
|
|
|
|
|
Dom.Mem.weak_update_heap ploc Dom.Val.Itv.top mem
|
|
|
|
@ -84,7 +82,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
|
|
|
|
|
mem
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let malloc size_exp =
|
|
|
|
|
let malloc size_exp =
|
|
|
|
|
let exec {pname; ret; node_hash; location; tenv} mem =
|
|
|
|
|
match ret with
|
|
|
|
|
| Some (id, _) ->
|
|
|
|
@ -109,7 +107,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
|
|
|
|
|
{exec; check}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let realloc src_exp size_exp =
|
|
|
|
|
let realloc src_exp size_exp =
|
|
|
|
|
let exec {ret; location; tenv} mem =
|
|
|
|
|
match ret with
|
|
|
|
|
| Some (id, _) ->
|
|
|
|
@ -131,7 +129,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
|
|
|
|
|
{exec; check}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let placement_new allocated_mem_exp =
|
|
|
|
|
let placement_new allocated_mem_exp =
|
|
|
|
|
let exec {ret} mem =
|
|
|
|
|
match ret with
|
|
|
|
|
| Some (id, _) ->
|
|
|
|
@ -143,7 +141,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
|
|
|
|
|
{exec; check= no_check}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let inferbo_min e1 e2 =
|
|
|
|
|
let inferbo_min e1 e2 =
|
|
|
|
|
let exec {ret} mem =
|
|
|
|
|
match ret with
|
|
|
|
|
| Some (id, _) ->
|
|
|
|
@ -157,7 +155,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
|
|
|
|
|
{exec; check= no_check}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let inferbo_set_size e1 e2 =
|
|
|
|
|
let inferbo_set_size e1 e2 =
|
|
|
|
|
let exec _model_env mem =
|
|
|
|
|
let locs = Sem.eval_locs e1 mem |> Dom.Val.get_pow_loc in
|
|
|
|
|
let size = Sem.eval e2 mem |> Dom.Val.get_itv in
|
|
|
|
@ -168,7 +166,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
|
|
|
|
|
{exec; check}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let model_by_value value ret mem =
|
|
|
|
|
let model_by_value value ret mem =
|
|
|
|
|
match ret with
|
|
|
|
|
| Some (id, _) ->
|
|
|
|
|
Dom.Mem.add_stack (Loc.of_id id) value mem
|
|
|
|
@ -178,17 +176,17 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
|
|
|
|
|
mem
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let by_value value =
|
|
|
|
|
let exec {ret} mem = model_by_value value ret mem in
|
|
|
|
|
{exec; check= no_check}
|
|
|
|
|
let by_value =
|
|
|
|
|
let exec ~value {ret} mem = model_by_value value ret mem in
|
|
|
|
|
fun value -> {exec= exec ~value; check= no_check}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let bottom =
|
|
|
|
|
let bottom =
|
|
|
|
|
let exec _model_env _mem = Bottom in
|
|
|
|
|
{exec; check= no_check}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let infer_print e =
|
|
|
|
|
let infer_print e =
|
|
|
|
|
let exec {location} mem =
|
|
|
|
|
L.(debug BufferOverrun Medium)
|
|
|
|
|
"@[<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}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let set_array_length array length_exp =
|
|
|
|
|
let set_array_length array length_exp =
|
|
|
|
|
let exec {pname; node_hash; location} mem =
|
|
|
|
|
match array with
|
|
|
|
|
| Exp.Lvar array_pvar, {Typ.desc= Typ.Tarray {elt; stride}} ->
|
|
|
|
@ -215,7 +213,7 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
|
|
|
|
|
{exec; check}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
module Split = struct
|
|
|
|
|
module Split = struct
|
|
|
|
|
let std_vector ~adds_at_least_one (vector_exp, vector_typ) location mem =
|
|
|
|
|
let traces = BufferOverrunTrace.(Call location |> singleton |> Set.singleton) 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
|
|
|
|
|
in
|
|
|
|
|
Dom.Mem.transform_mem ~f:(Dom.Val.plus increment) vector_size_locs mem
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
module Boost = struct
|
|
|
|
|
module Boost = struct
|
|
|
|
|
module Split = struct
|
|
|
|
|
let std_vector vector_arg =
|
|
|
|
|
let exec {location} mem =
|
|
|
|
|
Split.std_vector ~adds_at_least_one:true vector_arg location mem
|
|
|
|
|
in
|
|
|
|
|
let exec {location} mem = Split.std_vector ~adds_at_least_one:true vector_arg location mem in
|
|
|
|
|
{exec; check= no_check}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
module Folly = struct
|
|
|
|
|
module Folly = struct
|
|
|
|
|
module Split = struct
|
|
|
|
|
let std_vector vector_arg ignore_empty_opt =
|
|
|
|
|
let exec {location} mem =
|
|
|
|
@ -254,22 +250,22 @@ module Make (BoUtils : BufferOverrunUtils.S) = struct
|
|
|
|
|
in
|
|
|
|
|
{exec; check= no_check}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
module StdArray = struct
|
|
|
|
|
module StdArray = struct
|
|
|
|
|
let typ typ length =
|
|
|
|
|
let declare_local ~decl_local {pname; node_hash; location} loc ~inst_num ~dimension mem =
|
|
|
|
|
(* should this be deferred to the constructor? *)
|
|
|
|
|
let length = Some (IntLit.of_int64 length) in
|
|
|
|
|
BoUtils.Exec.decl_local_array ~decl_local pname ~node_hash location loc typ ~length
|
|
|
|
|
~inst_num ~dimension mem
|
|
|
|
|
BoUtils.Exec.decl_local_array ~decl_local pname ~node_hash location loc typ ~length ~inst_num
|
|
|
|
|
~dimension mem
|
|
|
|
|
in
|
|
|
|
|
let declare_symbolic ~decl_sym_val {pname; tenv; node_hash; location} ~depth loc ~inst_num
|
|
|
|
|
~new_sym_num ~new_alloc_num mem =
|
|
|
|
|
let offset = Itv.zero in
|
|
|
|
|
let size = Itv.of_int64 length in
|
|
|
|
|
BoUtils.Exec.decl_sym_arr ~decl_sym_val pname tenv ~node_hash location ~depth loc typ
|
|
|
|
|
~offset ~size ~inst_num ~new_sym_num ~new_alloc_num mem
|
|
|
|
|
BoUtils.Exec.decl_sym_arr ~decl_sym_val pname tenv ~node_hash location ~depth loc typ ~offset
|
|
|
|
|
~size ~inst_num ~new_sym_num ~new_alloc_num mem
|
|
|
|
|
in
|
|
|
|
|
{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 =
|
|
|
|
|
(no_model "local" pname location mem, inst_num)
|
|
|
|
|
in
|
|
|
|
|
let declare_symbolic ~decl_sym_val:_ {pname; location} ~depth:_ _loc ~inst_num:_
|
|
|
|
|
~new_sym_num:_ ~new_alloc_num:_ mem =
|
|
|
|
|
let declare_symbolic ~decl_sym_val:_ {pname; location} ~depth:_ _loc ~inst_num:_ ~new_sym_num:_
|
|
|
|
|
~new_alloc_num:_ mem =
|
|
|
|
|
no_model "symbolic" pname location mem
|
|
|
|
|
in
|
|
|
|
|
{declare_local; declare_symbolic}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
module Call = struct
|
|
|
|
|
module Call = struct
|
|
|
|
|
let dispatch : model ProcnameDispatcher.Call.dispatcher =
|
|
|
|
|
let open ProcnameDispatcher.Call 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 >:: "operator[]" $ capt_arg $+ capt_arg $!--> StdArray.at
|
|
|
|
|
; -"std" &:: "array" &::.*--> StdArray.no_model ]
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
module TypName = struct
|
|
|
|
|
module TypName = struct
|
|
|
|
|
let dispatch : typ_model ProcnameDispatcher.TypName.dispatcher =
|
|
|
|
|
let open ProcnameDispatcher.TypName in
|
|
|
|
|
make_dispatcher
|
|
|
|
|
[ -"std" &:: "array" < capt_typ `T &+ capt_int >--> StdArray.typ
|
|
|
|
|
; -"std" &:: "array" &::.*--> StdArray.no_typ_model ]
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|