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.

811 lines
24 KiB

(*
* Copyright (c) 2016 - present
*
* Programming Research Laboratory (ROPAS)
* Seoul National University, Korea
* 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 F = Format
module L = Logging
module MF = MarkupFormatter
let always_strong_update = true (* unsound but ok for bug catching *)
module Condition =
struct
type t = {
proc_name : Typ.Procname.t;
loc : Location.t;
id : string;
trace : trace;
idx : Itv.astate;
size : Itv.astate;
}
[@@deriving compare]
and trace = Intra of Typ.Procname.t
| Inter of Typ.Procname.t * Typ.Procname.t * Location.t
[@@deriving compare]
and astate = t
let set_size_pos : t -> t
= fun c ->
if Itv.Bound.lt (Itv.lb c.size) Itv.Bound.zero
then { c with size = Itv.make Itv.Bound.zero (Itv.ub c.size) }
else c
let string_of_location : Location.t -> string
= fun loc ->
let fname = SourceFile.to_string loc.Location.file in
let pos = Location.to_string loc in
F.fprintf F.str_formatter "%s:%s" fname pos;
F.flush_str_formatter ()
let pp_location : F.formatter -> t -> unit
= fun fmt c ->
F.fprintf fmt "%s" (string_of_location c.loc)
let pp : F.formatter -> t -> unit
= fun fmt c ->
let c = set_size_pos c in
if Config.bo_debug <= 1 then
F.fprintf fmt "%a < %a at %a" Itv.pp c.idx Itv.pp c.size pp_location c
else
match c.trace with
Inter (_, pname, loc) ->
let pname = Typ.Procname.to_string pname in
F.fprintf fmt "%a < %a at %a by call %s() at %s"
Itv.pp c.idx Itv.pp c.size pp_location c pname (string_of_location loc)
| Intra _ -> F.fprintf fmt "%a < %a at %a" Itv.pp c.idx Itv.pp c.size pp_location c
let get_location : t -> Location.t
= fun c -> c.loc
let get_trace : t -> trace
= fun c -> c.trace
let get_proc_name : t -> Typ.Procname.t
= fun c -> c.proc_name
let make : Typ.Procname.t -> Location.t -> string -> idx:Itv.t -> size:Itv.t -> t
= fun proc_name loc id ~idx ~size ->
{ proc_name; idx; size; loc; id ; trace = Intra proc_name }
let filter1 : t -> bool
= fun c ->
Itv.eq c.idx Itv.top || Itv.eq c.size Itv.top
|| Itv.Bound.eq (Itv.lb c.idx) Itv.Bound.MInf
|| Itv.Bound.eq (Itv.lb c.size) Itv.Bound.MInf
|| (Itv.eq c.idx Itv.nat && Itv.eq c.size Itv.nat)
let filter2 : t -> bool
= fun c ->
(* basically, alarms involving infinity are filtered *)
(not (Itv.is_finite c.idx) || not (Itv.is_finite c.size))
&& (* except the following cases *)
not ((Itv.Bound.is_not_infty (Itv.lb c.idx) && (* idx non-infty lb < 0 *)
Itv.Bound.lt (Itv.lb c.idx) Itv.Bound.zero)
||
(Itv.Bound.is_not_infty (Itv.lb c.idx) && (* idx non-infty lb > size lb *)
(Itv.Bound.gt (Itv.lb c.idx) (Itv.lb c.size)))
||
(Itv.Bound.is_not_infty (Itv.lb c.idx) && (* idx non-infty lb > size ub *)
(Itv.Bound.gt (Itv.lb c.idx) (Itv.ub c.size)))
||
(Itv.Bound.is_not_infty (Itv.ub c.idx) && (* idx non-infty ub > size lb *)
(Itv.Bound.gt (Itv.ub c.idx) (Itv.lb c.size)))
||
(Itv.Bound.is_not_infty (Itv.ub c.idx) && (* idx non-infty ub > size ub *)
(Itv.Bound.gt (Itv.ub c.idx) (Itv.ub c.size))))
(* check buffer overrun and return its confidence *)
let check : t -> string option
= fun c ->
(* idx = [il, iu], size = [sl, su], we want to check that 0 <= idx < size *)
let c' = set_size_pos c in (* if sl < 0, use sl' = 0 *)
let not_overrun = Itv.lt_sem c'.idx c'.size in
let not_underrun = Itv.le_sem Itv.zero c'.idx in
(* il >= 0 and iu < sl, definitely not an error *)
if Itv.eq not_overrun Itv.one && Itv.eq not_underrun Itv.one then
None
(* iu < 0 or il >= su, definitely an error *)
else if Itv.eq not_overrun Itv.zero || Itv.eq not_underrun Itv.zero then
Some Localise.BucketLevel.b1
(* su <= iu < +oo, most probably an error *)
else if Itv.Bound.is_not_infty (Itv.ub c.idx)
&& Itv.Bound.le (Itv.ub c.size) (Itv.ub c.idx) then
Some Localise.BucketLevel.b2
(* symbolic il >= sl, probably an error *)
else if Itv.Bound.is_symbolic (Itv.lb c.idx)
&& Itv.Bound.le (Itv.lb c'.size) (Itv.lb c.idx) then
Some Localise.BucketLevel.b3
(* other symbolic bounds are probably too noisy *)
else if Config.bo_debug <= 3 && (Itv.is_symbolic c.idx || Itv.is_symbolic c.size) then
None
else if filter1 c then
Some Localise.BucketLevel.b5
else if filter2 c then
Some Localise.BucketLevel.b3
else
Some Localise.BucketLevel.b2
let invalid : t -> bool
= fun x -> Itv.invalid x.idx || Itv.invalid x.size
let to_string : t -> string
= fun c ->
let c = set_size_pos c in
"Offset: " ^ Itv.to_string c.idx ^ " Size: " ^ Itv.to_string c.size
^ " @ " ^ string_of_location c.loc
^ (match c.trace with
Inter (_, pname, _) ->
" by call "
^ MF.monospaced_to_string (Typ.Procname.to_string pname ^ "()") ^ " "
| Intra _ -> "")
let subst : t -> Itv.Bound.t Itv.SubstMap.t -> Typ.Procname.t -> Typ.Procname.t -> Location.t -> t
= fun c subst_map caller_pname callee_pname loc ->
if Itv.is_symbolic c.idx || Itv.is_symbolic c.size then
{ c with idx = Itv.subst c.idx subst_map;
size = Itv.subst c.size subst_map;
trace = Inter (caller_pname, callee_pname, loc) }
else c
end
module ConditionSet =
struct
include AbstractDomain.FiniteSet (Condition)
module Map = Caml.Map.Make (Location)
let add_bo_safety
: Typ.Procname.t -> Location.t -> string -> idx:Itv.t -> size:Itv.t -> t -> t
= fun pname loc id ~idx ~size cond ->
add (Condition.make pname loc id ~idx ~size) cond
let subst : t -> Itv.Bound.t Itv.SubstMap.t -> Typ.Procname.t -> Typ.Procname.t -> Location.t -> t
= fun x subst_map caller_pname callee_pname loc ->
fold (fun e -> add (Condition.subst e subst_map caller_pname callee_pname loc)) x empty
let group : t -> t Map.t
= fun x ->
fold (fun cond map ->
let old_set = try Map.find cond.loc map with _ -> empty in
Map.add cond.loc (add cond old_set) map) x Map.empty
let pp_summary : F.formatter -> t -> unit
= fun fmt x ->
let pp_sep fmt () = F.fprintf fmt ", @," in
let pp_element fmt v = Condition.pp fmt v in
F.fprintf fmt "@[<v 0>Safety conditions:@,";
F.fprintf fmt "@[<hov 2>{ ";
F.pp_print_list ~pp_sep pp_element fmt (elements x);
F.fprintf fmt " }@]";
F.fprintf fmt "@]"
let pp : Format.formatter -> t -> unit
= fun fmt x ->
let pp_sep fmt () = F.fprintf fmt ", @," in
let pp_element fmt v = Condition.pp fmt v in
F.fprintf fmt "@[<v 2>Safety conditions :@,";
F.fprintf fmt "@[<hov 1>{";
F.pp_print_list ~pp_sep pp_element fmt (elements x);
F.fprintf fmt " }@]";
F.fprintf fmt "@]"
let rm_invalid : t -> t
= fun x -> filter (fun c -> not (Condition.invalid c)) x
end
module Val =
struct
type astate = {
itv : Itv.astate;
powloc : PowLoc.astate;
arrayblk : ArrayBlk.astate;
}
type t = astate
let bot : t
= { itv = Itv.bot; powloc = PowLoc.bot; arrayblk = ArrayBlk.bot }
let (<=) ~lhs ~rhs =
if phys_equal lhs rhs then true
else
Itv.(<=) ~lhs:(lhs.itv) ~rhs:(rhs.itv)
&& PowLoc.(<=) ~lhs:(lhs.powloc) ~rhs:(rhs.powloc)
&& ArrayBlk.(<=) ~lhs:(lhs.arrayblk) ~rhs:(rhs.arrayblk)
let widen ~prev ~next ~num_iters =
if phys_equal prev next then prev
else
{ itv = Itv.widen ~prev:(prev.itv) ~next:(next.itv) ~num_iters;
powloc = PowLoc.widen ~prev:(prev.powloc) ~next:(next.powloc) ~num_iters;
arrayblk = ArrayBlk.widen ~prev:(prev.arrayblk) ~next:(next.arrayblk) ~num_iters; }
let pp fmt x =
F.fprintf fmt "(%a, %a, %a)" Itv.pp x.itv PowLoc.pp x.powloc ArrayBlk.pp x.arrayblk
let join : t -> t -> t
= fun x y ->
if phys_equal x y then x
else
{ itv = Itv.join x.itv y.itv;
powloc = PowLoc.join x.powloc y.powloc;
arrayblk = ArrayBlk.join x.arrayblk y.arrayblk }
let rec joins : t list -> t
= function
| [] -> bot
| [a] -> a
| a :: b -> join a (joins b)
let get_itv : t -> Itv.t
= fun x -> x.itv
let get_pow_loc : t -> PowLoc.t
= fun x -> x.powloc
let get_array_blk : t -> ArrayBlk.astate
= fun x -> x.arrayblk
let get_array_locs : t -> PowLoc.t
= fun x -> ArrayBlk.get_pow_loc x.arrayblk
let get_all_locs : t -> PowLoc.t
= fun x -> PowLoc.join x.powloc (get_array_locs x)
let of_itv itv = { bot with itv }
let of_int n = of_itv (Itv.of_int n)
let of_itv : Itv.t -> t
= fun itv -> { bot with itv }
let of_pow_loc : PowLoc.t -> t
= fun x -> { bot with powloc = x }
let of_array_blk : ArrayBlk.astate -> t
= fun a -> { bot with arrayblk = a }
let modify_itv : Itv.t -> t -> t
= fun i x -> { x with itv = i }
let make_sym : Typ.Procname.t -> int -> t
= fun pname i -> { bot with itv = Itv.make_sym pname i }
let unknown_bit : t -> t
= fun x -> { x with itv = Itv.top }
let neg : t -> t
= fun x -> { x with itv = Itv.neg x.itv }
let lnot : t -> t
= fun x -> { x with itv = Itv.lnot x.itv }
let lift_itv : (Itv.t -> Itv.t -> Itv.t) -> t -> t -> t
= fun f x y -> { bot with itv = f x.itv y.itv }
let has_pointer : t -> bool
= fun x ->
not (PowLoc.is_bot x.powloc && ArrayBlk.is_bot x.arrayblk)
let lift_cmp_itv : (Itv.t -> Itv.t -> Itv.t) -> t -> t -> t
= fun f x y ->
if has_pointer x || has_pointer y then
{bot with itv = Itv.unknown_bool}
else lift_itv f x y
let plus : t -> t -> t
= fun x y ->
{ x with itv = Itv.plus x.itv y.itv; arrayblk = ArrayBlk.plus_offset x.arrayblk y.itv }
let minus : t -> t -> t
= fun x y ->
let n = Itv.join (Itv.minus x.itv y.itv) (ArrayBlk.diff x.arrayblk y.arrayblk) in
let a = ArrayBlk.minus_offset x.arrayblk y.itv in
{ bot with itv = n; arrayblk = a}
let mult : t -> t -> t
= lift_itv Itv.mult
let div : t -> t -> t
= lift_itv Itv.div
let mod_sem : t -> t -> t
= lift_itv Itv.mod_sem
let shiftlt : t -> t -> t
= lift_itv Itv.shiftlt
let shiftrt : t -> t -> t
= lift_itv Itv.shiftrt
let lt_sem : t -> t -> t
= lift_cmp_itv Itv.lt_sem
let gt_sem : t -> t -> t
= lift_cmp_itv Itv.gt_sem
let le_sem : t -> t -> t
= lift_cmp_itv Itv.le_sem
let ge_sem : t -> t -> t
= lift_cmp_itv Itv.ge_sem
let eq_sem : t -> t -> t
= lift_cmp_itv Itv.eq_sem
let ne_sem : t -> t -> t
= lift_cmp_itv Itv.ne_sem
let land_sem : t -> t -> t
= lift_itv Itv.land_sem
let lor_sem : t -> t -> t
= lift_itv Itv.lor_sem
let lift_prune1 : (Itv.t -> Itv.t) -> t -> t
= fun f x -> { x with itv = f x.itv }
let lift_prune2
: (Itv.t -> Itv.t -> Itv.t)
-> (ArrayBlk.astate -> ArrayBlk.astate -> ArrayBlk.astate) -> t -> t -> t
= fun f g x y ->
{ x with itv = f x.itv y.itv; arrayblk = g x.arrayblk y.arrayblk }
let prune_zero : t -> t
= lift_prune1 Itv.prune_zero
let prune_comp : Binop.t -> t -> t -> t
= fun c -> lift_prune2 (Itv.prune_comp c) (ArrayBlk.prune_comp c)
let prune_eq : t -> t -> t
= lift_prune2 Itv.prune_eq ArrayBlk.prune_eq
let prune_ne : t -> t -> t
= lift_prune2 Itv.prune_ne ArrayBlk.prune_eq
let plus_pi : t -> t -> t
= fun x y ->
{ bot with powloc = x.powloc; arrayblk = ArrayBlk.plus_offset x.arrayblk y.itv }
let minus_pi : t -> t -> t
= fun x y ->
{ bot with powloc = x.powloc; arrayblk = ArrayBlk.minus_offset x.arrayblk y.itv }
let minus_pp : t -> t -> t
= fun x y ->
(* when we cannot precisely follow the physical memory model, return top *)
if (not (PowLoc.is_bot x.powloc) && ArrayBlk.is_bot x.arrayblk) ||
(not (PowLoc.is_bot y.powloc) && ArrayBlk.is_bot y.arrayblk)
then { bot with itv = Itv.top }
else { bot with itv = ArrayBlk.diff x.arrayblk y.arrayblk }
let subst : t -> Itv.Bound.t Itv.SubstMap.t -> t
= fun x subst_map ->
{ x with itv = Itv.subst x.itv subst_map;
arrayblk = ArrayBlk.subst x.arrayblk subst_map }
let get_symbols : t -> Itv.Symbol.t list
= fun x ->
List.append (Itv.get_symbols x.itv) (ArrayBlk.get_symbols x.arrayblk)
let normalize : t -> t
= fun x ->
{ x with itv = Itv.normalize x.itv; arrayblk = ArrayBlk.normalize x.arrayblk }
let pp_summary : F.formatter -> t -> unit
= fun fmt x -> F.fprintf fmt "(%a, %a)" Itv.pp x.itv ArrayBlk.pp x.arrayblk
module Itv =
struct
let nat = of_itv Itv.nat
let m1_255 = of_itv Itv.m1_255
let pos = of_itv Itv.pos
let top = of_itv Itv.top
end
end
module Stack =
struct
include AbstractDomain.Map (Loc) (Val)
let bot = empty
let find : Loc.t -> astate -> Val.t
= fun l m ->
try find l m with
| Not_found -> Val.bot
let find_set : PowLoc.t -> astate -> Val.t
= fun locs mem ->
let find_join loc acc = Val.join acc (find loc mem) in
PowLoc.fold find_join locs Val.bot
let strong_update : PowLoc.t -> Val.astate -> astate -> astate
= fun locs v mem ->
PowLoc.fold (fun x -> add x v) locs mem
let weak_update : PowLoc.t -> Val.astate -> astate -> astate
= fun locs v mem ->
PowLoc.fold (fun x -> add x (Val.join v (find x mem))) locs mem
let pp_summary : F.formatter -> astate -> unit
= fun fmt mem ->
let pp_not_logical_var k v =
if Loc.is_logical_var k then () else
F.fprintf fmt "%a -> %a@," Loc.pp k Val.pp_summary v
in
iter pp_not_logical_var mem
end
module Heap =
struct
module PPMap =
struct
include PrettyPrintable.MakePPMap (Loc)
let pp_collection
: pp_item:(F.formatter -> 'a -> unit) -> F.formatter -> 'a list -> unit
= fun ~pp_item fmt c ->
let pp_sep fmt () = F.fprintf fmt ",@," in
F.pp_print_list ~pp_sep pp_item fmt c
let pp : pp_value:(F.formatter -> 'a -> unit) -> F.formatter -> 'a t -> unit
= fun ~pp_value fmt m ->
let pp_item fmt (k, v) =
F.fprintf fmt "%a -> %a" Loc.pp k pp_value v
in
F.fprintf fmt "@[<v 2>{ ";
pp_collection ~pp_item fmt (bindings m);
F.fprintf fmt " }@]"
end
include AbstractDomain.Map (Loc) (Val)
let bot = empty
let find : Loc.t -> astate -> Val.t
= fun l m ->
try find l m with
| Not_found -> Val.Itv.top
let find_set : PowLoc.t -> astate -> Val.t
= fun locs mem ->
let find_join loc acc = Val.join acc (find loc mem) in
PowLoc.fold find_join locs Val.bot
let strong_update : PowLoc.t -> Val.t -> astate -> astate
= fun locs v mem ->
PowLoc.fold (fun x -> add x v) locs mem
let weak_update : PowLoc.t -> Val.t -> astate -> astate
= fun locs v mem ->
PowLoc.fold (fun x -> add x (Val.join v (find x mem))) locs mem
let pp_summary : F.formatter -> astate -> unit
= fun fmt mem ->
let pp_map fmt (k, v) = F.fprintf fmt "%a -> %a" Loc.pp k Val.pp_summary v in
F.fprintf fmt "@[<v 2>{ ";
F.pp_print_list pp_map fmt (bindings mem);
F.fprintf fmt " }@]"
let get_symbols : astate -> Itv.Symbol.t list
= fun mem ->
List.concat_map ~f:(fun (_, v) -> Val.get_symbols v) (bindings mem)
let get_return : astate -> Val.t
= fun mem ->
let mem = filter (fun l _ -> Loc.is_return l) mem in
if is_empty mem then Val.bot else snd (choose mem)
end
module Alias =
struct
module M = Caml.Map.Make (Ident)
type t = Pvar.t M.t
type astate = t
let bot : t
= M.empty
let (<=) : lhs:t -> rhs:t -> bool
= fun ~lhs ~rhs ->
let is_in_rhs k v =
match M.find k rhs with
| v' -> Pvar.equal v v'
| exception Not_found -> false
in
M.for_all is_in_rhs lhs
let join : t -> t -> t
= fun x y ->
let join_v _ v1_opt v2_opt =
match v1_opt, v2_opt with
| None, None -> None
| Some v, None
| None, Some v -> Some v
| Some v1, Some v2 -> if Pvar.equal v1 v2 then Some v1 else assert false
in
M.merge join_v x y
let widen : prev:t -> next:t -> num_iters:int -> t
= fun ~prev ~next ~num_iters:_ -> join prev next
let pp : F.formatter -> t -> unit
= fun fmt x ->
let pp_sep fmt () = F.fprintf fmt ", @," in
let pp1 fmt (k, v) =
F.fprintf fmt "%a=%a" (Ident.pp Pp.text) k (Pvar.pp Pp.text) v
in
(* F.fprintf fmt "@[<v 0>Logical Variables :@,"; *)
F.fprintf fmt "@[<hov 2>{ @,";
F.pp_print_list ~pp_sep pp1 fmt (M.bindings x);
F.fprintf fmt " }@]";
F.fprintf fmt "@]"
let load : Ident.t -> Exp.t -> t -> t
= fun id exp m ->
match exp with
| Exp.Lvar x -> M.add id x m
| _ -> m
let store : Exp.t -> Exp.t -> t -> t
= fun e _ m ->
match e with
| Exp.Lvar x -> M.filter (fun _ y -> not (Pvar.equal x y)) m
| _ -> m
let find : Ident.t -> t -> Pvar.t option
= fun k m -> try Some (M.find k m) with Not_found -> None
end
module MemReach =
struct
type astate = { stack : Stack.astate; heap : Heap.astate; alias : Alias.astate }
type t = astate
let bot : t
= { stack = Stack.bot; heap = Heap.bot; alias = Alias.bot }
let (<=) ~lhs ~rhs =
if phys_equal lhs rhs then true
else
Stack.(<=) ~lhs:(lhs.stack) ~rhs:(rhs.stack)
&& Heap.(<=) ~lhs:(lhs.heap) ~rhs:(rhs.heap)
&& Alias.(<=) ~lhs:(lhs.alias) ~rhs:(rhs.alias)
let widen ~prev ~next ~num_iters =
if phys_equal prev next then prev
else
{ stack = Stack.widen ~prev:(prev.stack) ~next:(next.stack) ~num_iters;
heap = Heap.widen ~prev:(prev.heap) ~next:(next.heap) ~num_iters;
alias = Alias.widen ~prev:(prev.alias) ~next:(next.alias) ~num_iters; }
let join : t -> t -> t
= fun x y ->
{ stack = Stack.join x.stack y.stack;
heap = Heap.join x.heap y.heap;
alias = Alias.join x.alias y.alias }
let pp : F.formatter -> t -> unit
= fun fmt x ->
F.fprintf fmt "Stack:@;";
F.fprintf fmt "%a@;" Stack.pp x.stack;
F.fprintf fmt "Heap:@;";
F.fprintf fmt "%a" Heap.pp x.heap
let pp_summary : F.formatter -> t -> unit
= fun fmt x ->
F.fprintf fmt "@[<v 0>Parameters:@,";
F.fprintf fmt "%a" Heap.pp_summary x.heap ;
F.fprintf fmt "@]"
let find_stack : Loc.t -> t -> Val.t
= fun k m -> Stack.find k m.stack
let find_stack_set : PowLoc.t -> t -> Val.t
= fun k m -> Stack.find_set k m.stack
let find_heap : Loc.t -> t -> Val.t
= fun k m -> Heap.find k m.heap
let find_heap_set : PowLoc.t -> t -> Val.t
= fun k m -> Heap.find_set k m.heap
let find_alias : Ident.t -> t -> Pvar.t option
= fun k m -> Alias.find k m.alias
let load_alias : Ident.t -> Exp.t -> t -> t
= fun id e m -> { m with alias = Alias.load id e m.alias }
let store_alias : Exp.t -> Exp.t -> t -> t
= fun e1 e2 m -> { m with alias = Alias.store e1 e2 m.alias }
let add_stack : Loc.t -> Val.t -> t -> t
= fun k v m -> { m with stack = Stack.add k v m.stack }
let add_heap : Loc.t -> Val.t -> t -> t
= fun k v m -> { m with heap = Heap.add k v m.heap }
let strong_update_stack : PowLoc.t -> Val.t -> t -> t
= fun p v m -> { m with stack = Stack.strong_update p v m.stack }
let strong_update_heap : PowLoc.t -> Val.t -> t -> t
= fun p v m -> { m with heap = Heap.strong_update p v m.heap }
let weak_update_stack : PowLoc.t -> Val.t -> t -> t
= fun p v m -> { m with stack = Stack.weak_update p v m.stack }
let weak_update_heap : PowLoc.t -> Val.t -> t -> t
= fun p v m -> { m with heap = Heap.weak_update p v m.heap }
let get_heap_symbols : t -> Itv.Symbol.t list
= fun m -> Heap.get_symbols m.heap
let get_return : t -> Val.t
= fun m -> Heap.get_return m.heap
let can_strong_update : PowLoc.t -> bool
= fun ploc ->
if always_strong_update then true else
if Int.equal (PowLoc.cardinal ploc) 1 then Loc.is_var (PowLoc.choose ploc) else false
let update_mem : PowLoc.t -> Val.t -> t -> t
= fun ploc v s ->
if can_strong_update ploc
then strong_update_heap ploc v s
else
let () =
if Config.bo_debug >= 3 then
L.out "Weak update for %a <- %a@." PowLoc.pp ploc Val.pp v
in
weak_update_heap ploc v s
end
module Mem = struct
include AbstractDomain.BottomLifted (MemReach)
type t = astate
let bot : t = Bottom
let init : t = NonBottom (MemReach.bot)
let f_lift_default : 'a -> (MemReach.t -> 'a) -> t -> 'a =
fun default f m ->
match m with
| Bottom -> default
| NonBottom m' -> f m'
let f_lift : (MemReach.t -> MemReach.t) -> t -> t =
fun f ->
f_lift_default Bottom (fun m' -> NonBottom (f m'))
let pp_summary : F.formatter -> t -> unit
= fun fmt m ->
match m with
| Bottom -> F.fprintf fmt "unreachable"
| NonBottom m' -> MemReach.pp_summary fmt m'
let find_stack : Loc.t -> t -> Val.t
= fun k ->
f_lift_default Val.bot (MemReach.find_stack k)
let find_stack_set : PowLoc.t -> t -> Val.t
= fun k ->
f_lift_default Val.bot (MemReach.find_stack_set k)
let find_heap : Loc.t -> t -> Val.t
= fun k ->
f_lift_default Val.bot (MemReach.find_heap k)
let find_heap_set : PowLoc.t -> t -> Val.t
= fun k ->
f_lift_default Val.bot (MemReach.find_heap_set k)
let find_alias : Ident.t -> t -> Pvar.t option
= fun k ->
f_lift_default None (MemReach.find_alias k)
let load_alias : Ident.t -> Exp.t -> t -> t
= fun id e ->
f_lift (MemReach.load_alias id e)
let store_alias : Exp.t -> Exp.t -> t -> t
= fun e1 e2 ->
f_lift (MemReach.store_alias e1 e2)
let add_stack : Loc.t -> Val.t -> t -> t
= fun k v ->
f_lift (MemReach.add_stack k v)
let add_heap : Loc.t -> Val.t -> t -> t
= fun k v ->
f_lift (MemReach.add_heap k v)
let strong_update_stack : PowLoc.t -> Val.t -> t -> t
= fun p v ->
f_lift (MemReach.strong_update_stack p v)
let strong_update_heap : PowLoc.t -> Val.t -> t -> t
= fun p v ->
f_lift (MemReach.strong_update_heap p v)
let weak_update_stack : PowLoc.t -> Val.t -> t -> t
= fun p v ->
f_lift (MemReach.weak_update_stack p v)
let weak_update_heap : PowLoc.t -> Val.t -> t -> t
= fun p v ->
f_lift (MemReach.weak_update_heap p v)
let get_heap_symbols : t -> Itv.Symbol.t list
= f_lift_default [] MemReach.get_heap_symbols
let get_return : t -> Val.t
= f_lift_default Val.bot MemReach.get_return
let can_strong_update : PowLoc.t -> bool
= MemReach.can_strong_update
let update_mem : PowLoc.t -> Val.t -> t -> t
= fun ploc v ->
f_lift (MemReach.update_mem ploc v)
end
module Summary =
struct
type t = Mem.t * Mem.t * ConditionSet.t
let get_input : t -> Mem.t
= fst3
let get_output : t -> Mem.t
= snd3
let get_cond_set : t -> ConditionSet.t
= trd3
let get_symbols : t -> Itv.Symbol.t list
= fun s -> Mem.get_heap_symbols (get_input s)
let get_return : t -> Val.t
= fun s -> Mem.get_return (get_output s)
let pp_symbols : F.formatter -> t -> unit
= fun fmt s ->
let pp_sep fmt () = F.fprintf fmt ", @," in
F.fprintf fmt "@[<hov 2>Symbols: {";
F.pp_print_list ~pp_sep Itv.Symbol.pp fmt (get_symbols s);
F.fprintf fmt "}@]"
let pp_symbol_map : F.formatter -> t -> unit
= fun fmt s -> Mem.pp_summary fmt (get_input s)
let pp_return : F.formatter -> t -> unit
= fun fmt s -> F.fprintf fmt "Return value: %a" Val.pp_summary (get_return s)
let pp_summary : F.formatter -> t -> unit
= fun fmt s ->
F.fprintf fmt "%a@,%a@,%a" pp_symbol_map s pp_return s
ConditionSet.pp_summary (get_cond_set s)
let pp : F.formatter -> t -> unit
= fun fmt (entry_mem, exit_mem, condition_set) ->
F.fprintf fmt "%a@,%a@,%a@"
Mem.pp entry_mem Mem.pp exit_mem ConditionSet.pp condition_set
end