@ -14,8 +14,8 @@ module BaseMemory = PulseBaseMemory
module BaseAddressAttributes = PulseBaseAddressAttributes
module BaseAddressAttributes = PulseBaseAddressAttributes
(* * signature common to the "normal" [Domain], representing the post at the current program point,
(* * signature common to the "normal" [Domain], representing the post at the current program point,
and the inverted [ Inverted Domain] , representing the inferred pre - condition * )
and the inverted [ Pre Domain] , representing the inferred pre - condition * )
module type BaseDomain = sig
module type BaseDomain Sig = sig
(* private because the lattice is not the same for preconditions and postconditions so we don't
(* private because the lattice is not the same for preconditions and postconditions so we don't
want to confuse them * )
want to confuse them * )
type t = private BaseDomain . t
type t = private BaseDomain . t
@ -35,7 +35,7 @@ end
type base_domain = BaseDomain . t =
type base_domain = BaseDomain . t =
{ heap : BaseMemory . t ; stack : BaseStack . t ; attrs : BaseAddressAttributes . t }
{ heap : BaseMemory . t ; stack : BaseStack . t ; attrs : BaseAddressAttributes . t }
(* * operations common to [Domain] and [ Inverted Domain], see also the [BaseDomain] signature *)
(* * operations common to [Domain] and [ Pre Domain], see also the [BaseDomain] signature *)
module BaseDomainCommon = struct
module BaseDomainCommon = struct
let update ? stack ? heap ? attrs foot =
let update ? stack ? heap ? attrs foot =
let new_stack , new_heap , new_attrs =
let new_stack , new_heap , new_attrs =
@ -57,21 +57,14 @@ module BaseDomainCommon = struct
end
end
(* * represents the post abstract state at each program point *)
(* * represents the post abstract state at each program point *)
module Domain : BaseDomain = struct
module Domain : BaseDomain Sig = struct
include BaseDomainCommon
include BaseDomainCommon
include BaseDomain
include BaseDomain
end
end
(* NOTE: [PreDomain] and [Domain] theoretically differ in that [PreDomain] should be the inverted lattice of [Domain], but since we never actually join states or check implication the two collapse into one. *)
module PreDomain : BaseDomainSig = Domain
(* * represents the inferred pre-condition at each program point, biabduction style *)
(* * represents the inferred pre-condition at each program point, biabduction style *)
module InvertedDomain : BaseDomain = struct
include BaseDomainCommon
type t = BaseDomain . t
let empty = BaseDomain . empty
let pp = BaseDomain . pp
end
module SkippedTrace = struct
module SkippedTrace = struct
type t = PulseTrace . t [ @@ deriving compare ]
type t = PulseTrace . t [ @@ deriving compare ]
@ -93,7 +86,7 @@ module SkippedCalls = AbstractDomain.Map (Procname) (SkippedTrace)
(* * biabduction-style pre/post state + skipped calls *)
(* * biabduction-style pre/post state + skipped calls *)
type t =
type t =
{ post : Domain . t (* * state at the current program point *)
{ post : Domain . t (* * state at the current program point *)
; pre : Inverted Domain. t (* * inferred pre at the current program point *)
; pre : Pre Domain. t (* * inferred pre at the current program point *)
; skipped_calls : SkippedCalls . t (* * set of skipped calls *) }
; skipped_calls : SkippedCalls . t (* * set of skipped calls *) }
let get_pre { pre } = ( pre :> BaseDomain . t )
let get_pre { pre } = ( pre :> BaseDomain . t )
@ -102,7 +95,7 @@ let get_post {post} = (post :> BaseDomain.t)
let get_skipped_calls { skipped_calls } = skipped_calls
let get_skipped_calls { skipped_calls } = skipped_calls
let pp f { post ; pre } = F . fprintf f " @[<v>%a@;PRE=[%a]@] " Domain . pp post Inverted Domain. pp pre
let pp f { post ; pre } = F . fprintf f " @[<v>%a@;PRE=[%a]@] " Domain . pp post Pre Domain. pp pre
let leq ~ lhs ~ rhs =
let leq ~ lhs ~ rhs =
SkippedCalls . leq ~ lhs : lhs . skipped_calls ~ rhs : rhs . skipped_calls
SkippedCalls . leq ~ lhs : lhs . skipped_calls ~ rhs : rhs . skipped_calls
@ -147,7 +140,7 @@ module Stack = struct
(* HACK: do not record the history of values in the pre as they are unused *)
(* HACK: do not record the history of values in the pre as they are unused *)
let foot_stack = BaseStack . add var ( addr , [] ) ( astate . pre :> base_domain ) . stack in
let foot_stack = BaseStack . add var ( addr , [] ) ( astate . pre :> base_domain ) . stack in
let foot_heap = BaseMemory . register_address addr ( astate . pre :> base_domain ) . heap in
let foot_heap = BaseMemory . register_address addr ( astate . pre :> base_domain ) . heap in
Inverted Domain. update ~ stack : foot_stack ~ heap : foot_heap astate . pre
Pre Domain. update ~ stack : foot_stack ~ heap : foot_heap astate . pre
else astate . pre
else astate . pre
in
in
( { post = Domain . update astate . post ~ stack : post_stack
( { post = Domain . update astate . post ~ stack : post_stack
@ -186,7 +179,7 @@ module AddressAttributes = struct
L . d_printfln " Abducing %a:%a " AbstractValue . pp address Attribute . pp attribute ;
L . d_printfln " Abducing %a:%a " AbstractValue . pp address Attribute . pp attribute ;
let new_pre =
let new_pre =
if BaseMemory . mem address ( astate . pre :> base_domain ) . heap then
if BaseMemory . mem address ( astate . pre :> base_domain ) . heap then
Inverted Domain. update astate . pre
Pre Domain. update astate . pre
~ attrs : ( BaseAddressAttributes . add_one address attribute ( astate . pre :> base_domain ) . attrs )
~ attrs : ( BaseAddressAttributes . add_one address attribute ( astate . pre :> base_domain ) . attrs )
else astate . pre
else astate . pre
in
in
@ -285,7 +278,7 @@ module Memory = struct
else ( astate . pre :> base_domain ) . heap
else ( astate . pre :> base_domain ) . heap
in
in
( { post = Domain . update astate . post ~ heap : post_heap
( { post = Domain . update astate . post ~ heap : post_heap
; pre = Inverted Domain. update astate . pre ~ heap : foot_heap
; pre = Pre Domain. update astate . pre ~ heap : foot_heap
; skipped_calls = astate . skipped_calls }
; skipped_calls = astate . skipped_calls }
, addr_hist_dst )
, addr_hist_dst )
@ -306,15 +299,15 @@ let mk_initial proc_desc =
, ( AbstractValue . mk_fresh () , [ ValueHistory . FormalDeclared ( pvar , location ) ] ) ) )
, ( AbstractValue . mk_fresh () , [ ValueHistory . FormalDeclared ( pvar , location ) ] ) ) )
in
in
let initial_stack =
let initial_stack =
List . fold formals ~ init : ( Inverted Domain. empty :> BaseDomain . t ) . stack
List . fold formals ~ init : ( Pre Domain. empty :> BaseDomain . t ) . stack
~ f : ( fun stack ( formal , addr_loc ) -> BaseStack . add formal addr_loc stack )
~ f : ( fun stack ( formal , addr_loc ) -> BaseStack . add formal addr_loc stack )
in
in
let pre =
let pre =
let initial_heap =
let initial_heap =
List . fold formals ~ init : ( Inverted Domain. empty :> base_domain ) . heap
List . fold formals ~ init : ( Pre Domain. empty :> base_domain ) . heap ~ f : ( fun heap ( _ , ( addr , _ ) ) ->
~ f : ( fun heap ( _ , ( addr , _ ) ) -> BaseMemory . register_address addr heap )
BaseMemory . register_address addr heap )
in
in
Inverted Domain. update ~ stack : initial_stack ~ heap : initial_heap Inverted Domain. empty
Pre Domain. update ~ stack : initial_stack ~ heap : initial_heap Pre Domain. empty
in
in
let post = Domain . update ~ stack : initial_stack Domain . empty in
let post = Domain . update ~ stack : initial_stack Domain . empty in
let skipped_calls = SkippedCalls . empty in
let skipped_calls = SkippedCalls . empty in
@ -330,7 +323,7 @@ let add_skipped_calls pname trace astate =
let discard_unreachable ( { pre ; post } as astate ) =
let discard_unreachable ( { pre ; post } as astate ) =
let pre_addresses = BaseDomain . reachable_addresses ( pre :> BaseDomain . t ) in
let pre_addresses = BaseDomain . reachable_addresses ( pre :> BaseDomain . t ) in
let pre_new =
let pre_new =
Inverted Domain. filter_addr ~ f : ( fun address -> AbstractValue . Set . mem address pre_addresses ) pre
Pre Domain. filter_addr ~ f : ( fun address -> AbstractValue . Set . mem address pre_addresses ) pre
in
in
let post_addresses = BaseDomain . reachable_addresses ( post :> BaseDomain . t ) in
let post_addresses = BaseDomain . reachable_addresses ( post :> BaseDomain . t ) in
let all_addresses = AbstractValue . Set . union pre_addresses post_addresses in
let all_addresses = AbstractValue . Set . union pre_addresses post_addresses in
@ -372,7 +365,7 @@ module PrePost = struct
let pre_heap = deregister_empty ( astate . pre :> base_domain ) . heap in
let pre_heap = deregister_empty ( astate . pre :> base_domain ) . heap in
let post_heap = deregister_empty ( astate . post :> base_domain ) . heap in
let post_heap = deregister_empty ( astate . post :> base_domain ) . heap in
{ astate with
{ astate with
pre = Inverted Domain. update astate . pre ~ heap : pre_heap
pre = Pre Domain. update astate . pre ~ heap : pre_heap
; post = Domain . update ~ stack : post_stack ~ heap : post_heap astate . post }
; post = Domain . update ~ stack : post_stack ~ heap : post_heap astate . post }