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.
211 lines
7.3 KiB
211 lines
7.3 KiB
(*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*)
|
|
|
|
open! IStd
|
|
open PulseBasicInterface
|
|
open PulseDomainInterface
|
|
|
|
(** For [open]ing in other modules. *)
|
|
module Import : sig
|
|
type access_mode =
|
|
| Read
|
|
| Write
|
|
| NoAccess
|
|
(** The initialized-ness of the address is not checked when it evaluates a heap address
|
|
without actual memory access, for example, when evaluating [&x.f] we need to check
|
|
initialized-ness of [x], not that of [x.f]. *)
|
|
|
|
(** {2 Imported types for ease of use and so we can write variants without the corresponding
|
|
module prefix} *)
|
|
|
|
type 'abductive_domain_t execution_domain_base_t = 'abductive_domain_t ExecutionDomain.base_t =
|
|
| ContinueProgram of 'abductive_domain_t
|
|
| ExitProgram of AbductiveDomain.summary
|
|
| AbortProgram of AbductiveDomain.summary
|
|
| LatentAbortProgram of {astate: AbductiveDomain.summary; latent_issue: LatentIssue.t}
|
|
| LatentInvalidAccess of
|
|
{ astate: AbductiveDomain.summary
|
|
; address: AbstractValue.t
|
|
; must_be_valid: Trace.t * Invalidation.must_be_valid_reason option
|
|
; calling_context: (CallEvent.t * Location.t) list }
|
|
| ISLLatentMemoryError of AbductiveDomain.summary
|
|
|
|
type 'astate base_error = 'astate AccessResult.error =
|
|
| PotentialInvalidAccess of
|
|
{ astate: 'astate
|
|
; address: AbstractValue.t
|
|
; must_be_valid: Trace.t * Invalidation.must_be_valid_reason option }
|
|
| PotentialInvalidAccessSummary of
|
|
{ astate: AbductiveDomain.summary
|
|
; address: AbstractValue.t
|
|
; must_be_valid: Trace.t * Invalidation.must_be_valid_reason option }
|
|
| ReportableError of {astate: 'astate; diagnostic: Diagnostic.t}
|
|
| ISLError of 'astate
|
|
|
|
(** {2 Monadic syntax} *)
|
|
|
|
include module type of IResult.Let_syntax
|
|
|
|
val ( let<*> ) : 'a AccessResult.t -> ('a -> 'b AccessResult.t list) -> 'b AccessResult.t list
|
|
(** monadic "bind" but not really that turns an [AccessResult.t] into a list of [AccessResult.t]s
|
|
(not really because the first type is not an [AccessResult.t list] but just an
|
|
[AccessResult.t]) *)
|
|
|
|
val ( let<+> ) :
|
|
'a AccessResult.t
|
|
-> ('a -> 'abductive_domain_t)
|
|
-> 'abductive_domain_t execution_domain_base_t AccessResult.t list
|
|
(** monadic "map" but even less really that turns an [AccessResult.t] into an analysis result *)
|
|
end
|
|
|
|
include module type of Import
|
|
|
|
type t = AbductiveDomain.t
|
|
|
|
val check_addr_access :
|
|
access_mode -> Location.t -> AbstractValue.t * ValueHistory.t -> t -> t AccessResult.t
|
|
(** Check that the [address] is not known to be invalid *)
|
|
|
|
module Closures : sig
|
|
val check_captured_addresses : Location.t -> AbstractValue.t -> t -> t AccessResult.t
|
|
(** assert the validity of the addresses captured by the lambda *)
|
|
end
|
|
|
|
val eval :
|
|
access_mode -> Location.t -> Exp.t -> t -> (t * (AbstractValue.t * ValueHistory.t)) AccessResult.t
|
|
(** Use the stack and heap to evaluate the given expression down to an abstract address representing
|
|
its value.
|
|
|
|
Return an error state if it traverses some known invalid address or if the end destination is
|
|
known to be invalid. *)
|
|
|
|
val eval_structure_isl :
|
|
access_mode
|
|
-> Location.t
|
|
-> Exp.t
|
|
-> t
|
|
-> (bool * (t * (AbstractValue.t * ValueHistory.t)) AccessResult.t list) AccessResult.t
|
|
(** Similar to eval but apply to data structures and ISL abduction. Return a list of abduced states
|
|
(ISLOk and ISLErs); The boolean indicates whether it is data structures or not. *)
|
|
|
|
val prune : Location.t -> condition:Exp.t -> t -> t AccessResult.t
|
|
|
|
val eval_deref : Location.t -> Exp.t -> t -> (t * (AbstractValue.t * ValueHistory.t)) AccessResult.t
|
|
(** Like [eval] but evaluates [*exp]. *)
|
|
|
|
val eval_deref_isl :
|
|
Location.t -> Exp.t -> t -> (t * (AbstractValue.t * ValueHistory.t)) AccessResult.t list
|
|
|
|
val eval_access :
|
|
access_mode
|
|
-> Location.t
|
|
-> AbstractValue.t * ValueHistory.t
|
|
-> BaseMemory.Access.t
|
|
-> t
|
|
-> (t * (AbstractValue.t * ValueHistory.t)) AccessResult.t
|
|
(** Like [eval] but starts from an address instead of an expression, checks that it is valid, and if
|
|
so dereferences it according to the access. *)
|
|
|
|
val havoc_id : Ident.t -> ValueHistory.t -> t -> t
|
|
|
|
val havoc_field :
|
|
Location.t
|
|
-> AbstractValue.t * ValueHistory.t
|
|
-> Fieldname.t
|
|
-> ValueHistory.t
|
|
-> t
|
|
-> t AccessResult.t
|
|
|
|
val realloc_pvar : Tenv.t -> Pvar.t -> Typ.t -> Location.t -> t -> t
|
|
|
|
val write_id : Ident.t -> AbstractValue.t * ValueHistory.t -> t -> t
|
|
|
|
val write_field :
|
|
Location.t
|
|
-> ref:AbstractValue.t * ValueHistory.t
|
|
-> Fieldname.t
|
|
-> obj:AbstractValue.t * ValueHistory.t
|
|
-> t
|
|
-> t AccessResult.t
|
|
(** write the edge [ref --.field--> obj] *)
|
|
|
|
val write_arr_index :
|
|
Location.t
|
|
-> ref:AbstractValue.t * ValueHistory.t
|
|
-> index:AbstractValue.t
|
|
-> obj:AbstractValue.t * ValueHistory.t
|
|
-> t
|
|
-> t AccessResult.t
|
|
(** write the edge [ref\[index\]--> obj] *)
|
|
|
|
val write_deref :
|
|
Location.t
|
|
-> ref:AbstractValue.t * ValueHistory.t
|
|
-> obj:AbstractValue.t * ValueHistory.t
|
|
-> t
|
|
-> t AccessResult.t
|
|
(** write the edge [ref --*--> obj] *)
|
|
|
|
val write_deref_biad_isl :
|
|
Location.t
|
|
-> ref:AbstractValue.t * ValueHistory.t
|
|
-> AbstractValue.t HilExp.Access.t
|
|
-> obj:AbstractValue.t * ValueHistory.t
|
|
-> t
|
|
-> t AccessResult.t list
|
|
|
|
val invalidate :
|
|
Location.t -> Invalidation.t -> AbstractValue.t * ValueHistory.t -> t -> t AccessResult.t
|
|
(** record that the address is invalid *)
|
|
|
|
val invalidate_biad_isl :
|
|
Location.t -> Invalidation.t -> AbstractValue.t * ValueHistory.t -> t -> t AccessResult.t list
|
|
(** record that the address is invalid. If the address has not been allocated, abduce ISL specs for
|
|
both invalid (null, free, unint) and allocated heap. *)
|
|
|
|
val allocate : Procname.t -> Location.t -> AbstractValue.t * ValueHistory.t -> t -> t
|
|
|
|
val add_dynamic_type : Typ.t -> AbstractValue.t -> t -> t
|
|
|
|
val remove_allocation_attr : AbstractValue.t -> t -> t
|
|
|
|
val invalidate_access :
|
|
Location.t
|
|
-> Invalidation.t
|
|
-> AbstractValue.t * ValueHistory.t
|
|
-> BaseMemory.Access.t
|
|
-> t
|
|
-> t AccessResult.t
|
|
(** record that what the address points via the access to is invalid *)
|
|
|
|
val invalidate_array_elements :
|
|
Location.t -> Invalidation.t -> AbstractValue.t * ValueHistory.t -> t -> t AccessResult.t
|
|
(** record that all the array elements that address points to is invalid *)
|
|
|
|
val shallow_copy :
|
|
Location.t
|
|
-> AbstractValue.t * ValueHistory.t
|
|
-> t
|
|
-> (t * (AbstractValue.t * ValueHistory.t)) AccessResult.t
|
|
(** returns the address of a new cell with the same edges as the original *)
|
|
|
|
val get_dynamic_type_unreachable_values : Var.t list -> t -> (Var.t * Typ.t) list
|
|
(** Given a list of variables, computes the unreachable values if the variables were removed from
|
|
the stack, then return the dynamic types of those values if they are available *)
|
|
|
|
val remove_vars : Tenv.t -> Var.t list -> Location.t -> t -> t AccessResult.t
|
|
|
|
val check_address_escape :
|
|
Location.t -> Procdesc.t -> AbstractValue.t -> ValueHistory.t -> t -> t AccessResult.t
|
|
|
|
val get_captured_actuals :
|
|
Location.t
|
|
-> captured_vars:(Var.t * CapturedVar.capture_mode * Typ.t) list
|
|
-> actual_closure:AbstractValue.t * ValueHistory.t
|
|
-> t
|
|
-> (t * (Var.t * ((AbstractValue.t * ValueHistory.t) * Typ.t)) list) AccessResult.t
|