@ -11,63 +11,20 @@ open PulseBasicInterface
(* {2 Abstract domain description } *)
(* {2 Abstract domain description } *)
(* * An abstract address in memory. *)
module AbstractAddress : sig
type t = private int [ @@ deriving compare ]
val equal : t -> t -> bool
val mk_fresh : unit -> t
val pp : F . formatter -> t -> unit
val init : unit -> unit
type state
val get_state : unit -> state
val set_state : state -> unit
end = struct
type t = int [ @@ deriving compare ]
let equal = [ % compare . equal : t ]
let next_fresh = ref 1
let mk_fresh () =
let l = ! next_fresh in
incr next_fresh ; l
let pp f l = F . fprintf f " v%d " l
let init () = next_fresh := 1
type state = int
let get_state () = ! next_fresh
let set_state counter = next_fresh := counter
end
module AbstractAddressSet = PrettyPrintable . MakePPSet ( AbstractAddress )
module AbstractAddressMap = PrettyPrintable . MakePPMap ( AbstractAddress )
(* {3 Heap domain } *)
(* {3 Heap domain } *)
module AddrTracePair = struct
module AddrTracePair = struct
type t = Abstract Address . t * ValueHistory . t [ @@ deriving compare ]
type t = AbstractValue . t * ValueHistory . t [ @@ deriving compare ]
let pp f addr_trace =
let pp f addr_trace =
if Config . debug_level_analysis > = 3 then
if Config . debug_level_analysis > = 3 then
Pp . pair ~ fst : Abstract Address . pp ~ snd : ValueHistory . pp f addr_trace
Pp . pair ~ fst : AbstractValue . pp ~ snd : ValueHistory . pp f addr_trace
else Abstract Address . pp f ( fst addr_trace )
else AbstractValue . pp f ( fst addr_trace )
end
end
module Memory : sig
module Memory : sig
module Access : sig
module Access : sig
include PrettyPrintable . PrintableOrderedType with type t = Abstract Address . t HilExp . Access . t
include PrettyPrintable . PrintableOrderedType with type t = AbstractValue . t HilExp . Access . t
val equal : t -> t -> bool
val equal : t -> t -> bool
end
end
@ -84,54 +41,54 @@ module Memory : sig
val empty : t
val empty : t
val filter : ( Abstract Address . t -> bool ) -> t -> t
val filter : ( Abstract Value . t -> bool ) -> t -> t
val filter_heap : ( Abstract Address . t -> edges -> bool ) -> t -> t
val filter_heap : ( Abstract Value . t -> edges -> bool ) -> t -> t
val find_opt : Abstract Address . t -> t -> cell option
val find_opt : Abstract Value . t -> t -> cell option
val fold_attrs : ( Abstract Address . t -> Attributes . t -> ' acc -> ' acc ) -> t -> ' acc -> ' acc
val fold_attrs : ( Abstract Value . t -> Attributes . t -> ' acc -> ' acc ) -> t -> ' acc -> ' acc
val set_attrs : Abstract Address . t -> Attributes . t -> t -> t
val set_attrs : Abstract Value . t -> Attributes . t -> t -> t
val set_edges : Abstract Address . t -> edges -> t -> t
val set_edges : Abstract Value . t -> edges -> t -> t
val set_cell : Abstract Address . t -> cell -> t -> t
val set_cell : Abstract Value . t -> cell -> t -> t
val find_edges_opt : Abstract Address . t -> t -> edges option
val find_edges_opt : Abstract Value . t -> t -> edges option
val mem_edges : Abstract Address . t -> t -> bool
val mem_edges : Abstract Value . t -> t -> bool
val pp_heap : F . formatter -> t -> unit
val pp_heap : F . formatter -> t -> unit
val pp_attributes : F . formatter -> t -> unit
val pp_attributes : F . formatter -> t -> unit
val register_address : Abstract Address . t -> t -> t
val register_address : Abstract Value . t -> t -> t
val add_edge : Abstract Address . t -> Access . t -> AddrTracePair . t -> t -> t
val add_edge : Abstract Value . t -> Access . t -> AddrTracePair . t -> t -> t
val find_edge_opt : Abstract Address . t -> Access . t -> t -> AddrTracePair . t option
val find_edge_opt : Abstract Value . t -> Access . t -> t -> AddrTracePair . t option
val add_attribute : Abstract Address . t -> Attribute . t -> t -> t
val add_attribute : Abstract Value . t -> Attribute . t -> t -> t
val invalidate : Abstract Address . t * ValueHistory . t -> Invalidation . t -> Location . t -> t -> t
val invalidate : Abstract Value . t * ValueHistory . t -> Invalidation . t -> Location . t -> t -> t
val check_valid : Abstract Address . t -> t -> ( unit , Invalidation . t Trace . t ) result
val check_valid : Abstract Value . t -> t -> ( unit , Invalidation . t Trace . t ) result
val get_closure_proc_name : Abstract Address . t -> t -> Typ . Procname . t option
val get_closure_proc_name : Abstract Value . t -> t -> Typ . Procname . t option
val get_constant : Abstract Address . t -> t -> Const . t option
val get_constant : Abstract Value . t -> t -> Const . t option
val std_vector_reserve : Abstract Address . t -> t -> t
val std_vector_reserve : Abstract Value . t -> t -> t
val is_std_vector_reserved : Abstract Address . t -> t -> bool
val is_std_vector_reserved : Abstract Value . t -> t -> bool
end = struct
end = struct
module Access = struct
module Access = struct
type t = Abstract Address . t HilExp . Access . t [ @@ deriving compare ]
type t = Abstract Value . t HilExp . Access . t [ @@ deriving compare ]
let equal = [ % compare . equal : t ]
let equal = [ % compare . equal : t ]
let pp = HilExp . Access . pp Abstract Address . pp
let pp = HilExp . Access . pp Abstract Value . pp
end
end
module Edges = PrettyPrintable . MakePPMap ( Access )
module Edges = PrettyPrintable . MakePPMap ( Access )
@ -142,7 +99,7 @@ end = struct
type cell = edges * Attributes . t
type cell = edges * Attributes . t
module Graph = PrettyPrintable . MakePPMap ( Abstract Address )
module Graph = PrettyPrintable . MakePPMap ( Abstract Value )
type t = edges Graph . t * Attributes . t Graph . t
type t = edges Graph . t * Attributes . t Graph . t
@ -184,7 +141,7 @@ end = struct
let check_valid address memory =
let check_valid address memory =
L . d_printfln " Checking validity of %a " Abstract Address . pp address ;
L . d_printfln " Checking validity of %a " Abstract Value . pp address ;
match Graph . find_opt address ( snd memory ) | > Option . bind ~ f : Attributes . get_invalid with
match Graph . find_opt address ( snd memory ) | > Option . bind ~ f : Attributes . get_invalid with
| Some invalidation ->
| Some invalidation ->
Error invalidation
Error invalidation
@ -295,20 +252,20 @@ let empty =
[ rhs_to_lhs ] ) between the addresses of [ lhs ] and [ rhs ] such that [ lhs_to_rhs ( reachable ( lhs ) ) =
[ rhs_to_lhs ] ) between the addresses of [ lhs ] and [ rhs ] such that [ lhs_to_rhs ( reachable ( lhs ) ) =
reachable ( rhs ) ] ( where addresses are reachable if they are reachable from stack variables ) . * )
reachable ( rhs ) ] ( where addresses are reachable if they are reachable from stack variables ) . * )
module GraphComparison = struct
module GraphComparison = struct
module AddressMap = PrettyPrintable . MakePPMap ( Abstract Address )
module AddressMap = PrettyPrintable . MakePPMap ( Abstract Value )
(* * translation between the abstract values on the LHS and the ones on the RHS *)
(* * translation between the abstract values on the LHS and the ones on the RHS *)
type mapping =
type mapping =
{ rhs_to_lhs : Abstract Address . t AddressMap . t (* * map from RHS values to LHS *)
{ rhs_to_lhs : Abstract Value . t AddressMap . t (* * map from RHS values to LHS *)
; lhs_to_rhs : Abstract Address . t AddressMap . t (* * inverse map from [rhs_to_lhs] *) }
; lhs_to_rhs : Abstract Value . t AddressMap . t (* * inverse map from [rhs_to_lhs] *) }
let empty_mapping = { rhs_to_lhs = AddressMap . empty ; lhs_to_rhs = AddressMap . empty }
let empty_mapping = { rhs_to_lhs = AddressMap . empty ; lhs_to_rhs = AddressMap . empty }
let pp_mapping fmt { rhs_to_lhs ; lhs_to_rhs } =
let pp_mapping fmt { rhs_to_lhs ; lhs_to_rhs } =
F . fprintf fmt " @[<v>{ rhs_to_lhs=@[<hv2>%a@];@,lhs_to_rhs=@[<hv2>%a@];@,}@] "
F . fprintf fmt " @[<v>{ rhs_to_lhs=@[<hv2>%a@];@,lhs_to_rhs=@[<hv2>%a@];@,}@] "
( AddressMap . pp ~ pp_value : Abstract Address . pp )
( AddressMap . pp ~ pp_value : Abstract Value . pp )
rhs_to_lhs
rhs_to_lhs
( AddressMap . pp ~ pp_value : Abstract Address . pp )
( AddressMap . pp ~ pp_value : Abstract Value . pp )
lhs_to_rhs
lhs_to_rhs
@ -316,13 +273,13 @@ module GraphComparison = struct
let record_equal ~ addr_lhs ~ addr_rhs mapping =
let record_equal ~ addr_lhs ~ addr_rhs mapping =
(* have we seen [addr_lhs] before?.. *)
(* have we seen [addr_lhs] before?.. *)
match AddressMap . find_opt addr_lhs mapping . lhs_to_rhs with
match AddressMap . find_opt addr_lhs mapping . lhs_to_rhs with
| Some addr_rhs' when not ( Abstract Address . equal addr_rhs addr_rhs' ) ->
| Some addr_rhs' when not ( Abstract Value . equal addr_rhs addr_rhs' ) ->
(* ...yes, but it was bound to another address *)
(* ...yes, but it was bound to another address *)
L . d_printfln
L . d_printfln
" Aliasing in LHS not in RHS: LHS address %a in current already bound to %a, not %a@ \n \
" Aliasing in LHS not in RHS: LHS address %a in current already bound to %a, not %a@ \n \
State = % a "
State = % a "
Abstract Address. pp addr_lhs AbstractAddress . pp addr_rhs' AbstractAddress . pp addr_rhs
Abstract Value. pp addr_lhs AbstractValue . pp addr_rhs' AbstractValue . pp addr_rhs pp_mapping
pp_mapping mapping ;
mapping ;
` AliasingLHS
` AliasingLHS
| Some _ addr_rhs (* [_addr_rhs = addr_rhs] *) ->
| Some _ addr_rhs (* [_addr_rhs = addr_rhs] *) ->
` AlreadyVisited
` AlreadyVisited
@ -335,7 +292,7 @@ module GraphComparison = struct
L . d_printfln
L . d_printfln
" Aliasing in RHS not in LHS: RHS address %a in current already bound to %a, not %a@ \n \
" Aliasing in RHS not in LHS: RHS address %a in current already bound to %a, not %a@ \n \
State = % a "
State = % a "
Abstract Address. pp addr_rhs AbstractAddress . pp addr_lhs' AbstractAddress . pp addr_lhs
Abstract Value. pp addr_rhs AbstractValue . pp addr_lhs' AbstractValue . pp addr_lhs
pp_mapping mapping ;
pp_mapping mapping ;
` AliasingRHS
` AliasingRHS
| None ->
| None ->
@ -354,7 +311,7 @@ module GraphComparison = struct
(* * can we extend [mapping] so that the subgraph of [lhs] rooted at [addr_lhs] is isomorphic to
(* * can we extend [mapping] so that the subgraph of [lhs] rooted at [addr_lhs] is isomorphic to
the subgraph of [ rhs ] rooted at [ addr_rhs ] ? * )
the subgraph of [ rhs ] rooted at [ addr_rhs ] ? * )
let rec isograph_map_from_address ~ lhs ~ addr_lhs ~ rhs ~ addr_rhs mapping =
let rec isograph_map_from_address ~ lhs ~ addr_lhs ~ rhs ~ addr_rhs mapping =
L . d_printfln " %a<->%a@ \n " Abstract Address. pp addr_lhs AbstractAddress . pp addr_rhs ;
L . d_printfln " %a<->%a@ \n " Abstract Value. pp addr_lhs AbstractValue . pp addr_rhs ;
match record_equal mapping ~ addr_lhs ~ addr_rhs with
match record_equal mapping ~ addr_lhs ~ addr_rhs with
| ` AlreadyVisited ->
| ` AlreadyVisited ->
IsomorphicUpTo mapping
IsomorphicUpTo mapping
@ -449,12 +406,12 @@ module GraphVisit : sig
-> t
-> t
-> init : ' accum
-> init : ' accum
-> f : ( ' accum
-> f : ( ' accum
-> Abstract Address . t
-> Abstract Value . t
-> Var . t
-> Var . t
-> Memory . Access . t list
-> Memory . Access . t list
-> ( ' accum , ' final ) Base . Continue_or_stop . t )
-> ( ' accum , ' final ) Base . Continue_or_stop . t )
-> finish : ( ' accum -> ' final )
-> finish : ( ' accum -> ' final )
-> Abstract Address Set. t * ' final
-> Abstract Value. Set. t * ' final
(* * Generic graph traversal of the memory starting from each variable in the stack that pass
(* * Generic graph traversal of the memory starting from each variable in the stack that pass
[ var_filter ] , in order . Returns the result of folding over every address in the graph and the
[ var_filter ] , in order . Returns the result of folding over every address in the graph and the
set of addresses that have been visited before [ f ] returned [ Stop ] or all reachable addresses
set of addresses that have been visited before [ f ] returned [ Stop ] or all reachable addresses
@ -464,9 +421,9 @@ end = struct
open Base . Continue_or_stop
open Base . Continue_or_stop
let visit address visited =
let visit address visited =
if Abstract Address Set. mem address visited then ` AlreadyVisited
if Abstract Value. Set. mem address visited then ` AlreadyVisited
else
else
let visited = Abstract Address Set. add address visited in
let visited = Abstract Value. Set. add address visited in
` NotAlreadyVisited visited
` NotAlreadyVisited visited
@ -501,7 +458,7 @@ end = struct
let fold ~ var_filter astate ~ init ~ f ~ finish =
let fold ~ var_filter astate ~ init ~ f ~ finish =
let finish ( visited , accum ) = ( visited , finish accum ) in
let finish ( visited , accum ) = ( visited , finish accum ) in
let init = ( Abstract Address Set. empty , init ) in
let init = ( Abstract Value. Set. empty , init ) in
Container . fold_until astate . stack
Container . fold_until astate . stack
~ fold : ( IContainer . fold_of_pervasives_map_fold ~ fold : Stack . fold ) ~ init ~ finish
~ fold : ( IContainer . fold_of_pervasives_map_fold ~ fold : Stack . fold ) ~ init ~ finish
~ f : ( fun visited_accum ( var , ( address , _ loc ) ) ->
~ f : ( fun visited_accum ( var , ( address , _ loc ) ) ->