Module Pulselib__PulseOperations

module Import : sig ... end

For opening in other modules.

include module type of Import
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.

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 Pulselib.PulseDomainInterface.ExecutionDomain.base_t =
| ContinueProgram of 'abductive_domain_t
| ExitProgram of Pulselib.PulseDomainInterface.AbductiveDomain.summary
| AbortProgram of Pulselib.PulseDomainInterface.AbductiveDomain.summary
| LatentAbortProgram of {
astate : Pulselib.PulseDomainInterface.AbductiveDomain.summary;
latent_issue : Pulselib.PulseDomainInterface.LatentIssue.t;
}
| LatentInvalidAccess of {
astate : Pulselib.PulseDomainInterface.AbductiveDomain.summary;
address : Pulselib.PulseBasicInterface.AbstractValue.t;
must_be_valid : Pulselib.PulseBasicInterface.Trace.t * Pulselib.PulseBasicInterface.Invalidation.must_be_valid_reason option;
calling_context : (Pulselib.PulseBasicInterface.CallEvent.t * IBase.Location.t) list;
}
| ISLLatentMemoryError of Pulselib.PulseDomainInterface.AbductiveDomain.summary
type 'astate base_error = 'astate Pulselib.PulseDomainInterface.AccessResult.error =
| PotentialInvalidAccess of {
astate : 'astate;
address : Pulselib.PulseBasicInterface.AbstractValue.t;
must_be_valid : Pulselib.PulseBasicInterface.Trace.t * Pulselib.PulseBasicInterface.Invalidation.must_be_valid_reason option;
}
| PotentialInvalidAccessSummary of {
astate : Pulselib.PulseDomainInterface.AbductiveDomain.summary;
address : Pulselib.PulseBasicInterface.AbstractValue.t;
must_be_valid : Pulselib.PulseBasicInterface.Trace.t * Pulselib.PulseBasicInterface.Invalidation.must_be_valid_reason option;
}
| ReportableError of {
astate : 'astate;
diagnostic : Pulselib.PulseBasicInterface.Diagnostic.t;
}
| ReportableErrorSummary of {
astate : Pulselib.PulseDomainInterface.AbductiveDomain.summary;
diagnostic : Pulselib.PulseBasicInterface.Diagnostic.t;
}
| ISLError of 'astate

Monadic syntax

include module type of IStdlib.IResult.Let_syntax
include module type of IStdlib.IStd.Result.Monad_infix
val (>>=) : ('a'e) Core_kernel__Result.t -> ('a -> ('b'e) Core_kernel__Result.t) -> ('b'e) Core_kernel__Result.t
val (>>|) : ('a'e) Core_kernel__Result.t -> ('a -> 'b) -> ('b'e) Core_kernel__Result.t
val let+ : ('ok'err) IStdlib.IStd.result -> ('ok -> 'okk) -> ('okk'err) IStdlib.IStd.result
val let* : ('ok'err) IStdlib.IStd.result -> ('ok -> ('okk'err) IStdlib.IStd.result) -> ('okk'err) IStdlib.IStd.result
val let<*> : 'a Pulselib.PulseDomainInterface.AccessResult.t -> ('a -> 'b Pulselib.PulseDomainInterface.AccessResult.t list) -> 'b Pulselib.PulseDomainInterface.AccessResult.t list

monadic "bind" but not really that turns an AccessResult.t into a list of AccessResult.ts (not really because the first type is not an AccessResult.t list but just an AccessResult.t)

val let<+> : 'a Pulselib.PulseDomainInterface.AccessResult.t -> ('a -> 'abductive_domain_t) -> 'abductive_domain_t execution_domain_base_t Pulselib.PulseDomainInterface.AccessResult.t list

monadic "map" but even less really that turns an AccessResult.t into an analysis result

type t = Pulselib.PulseDomainInterface.AbductiveDomain.t
val check_addr_access : ?⁠must_be_valid_reason:Pulselib.PulseBasicInterface.Invalidation.must_be_valid_reason -> access_mode -> IBase.Location.t -> (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> t -> t Pulselib.PulseDomainInterface.AccessResult.t

Check that the address is not known to be invalid

module Closures : sig ... end
val eval : access_mode -> IBase.Location.t -> IR.Exp.t -> t -> (t * (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t)) Pulselib.PulseDomainInterface.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 -> IBase.Location.t -> IR.Exp.t -> t -> (bool * (t * (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t)) Pulselib.PulseDomainInterface.AccessResult.t list) Pulselib.PulseDomainInterface.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 : IBase.Location.t -> condition:IR.Exp.t -> t -> t Pulselib.PulseDomainInterface.AccessResult.t
val eval_deref : ?⁠must_be_valid_reason:Pulselib.PulseBasicInterface.Invalidation.must_be_valid_reason -> IBase.Location.t -> IR.Exp.t -> t -> (t * (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t)) Pulselib.PulseDomainInterface.AccessResult.t

Like eval but evaluates *exp.

val eval_deref_isl : IBase.Location.t -> IR.Exp.t -> t -> (t * (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t)) Pulselib.PulseDomainInterface.AccessResult.t list
val eval_access : ?⁠must_be_valid_reason:Pulselib.PulseBasicInterface.Invalidation.must_be_valid_reason -> access_mode -> IBase.Location.t -> (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> Pulselib.PulseDomainInterface.BaseMemory.Access.t -> t -> (t * (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t)) Pulselib.PulseDomainInterface.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 eval_deref_access : ?⁠must_be_valid_reason:Pulselib.PulseBasicInterface.Invalidation.must_be_valid_reason -> access_mode -> IBase.Location.t -> (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> Pulselib.PulseDomainInterface.BaseMemory.Access.t -> t -> (t * (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t)) Pulselib.PulseDomainInterface.AccessResult.t

Like eval_access but does additional dereference.

val eval_proc_name : IBase.Location.t -> IR.Exp.t -> t -> (t * IR.Procname.t option) Pulselib.PulseDomainInterface.AccessResult.t
val havoc_id : IR.Ident.t -> Pulselib.PulseBasicInterface.ValueHistory.t -> t -> t
val havoc_deref_field : IBase.Location.t -> (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> IR.Fieldname.t -> Pulselib.PulseBasicInterface.ValueHistory.t -> t -> t Pulselib.PulseDomainInterface.AccessResult.t

Havoc dereferenced field address.

val realloc_pvar : IR.Tenv.t -> IR.Pvar.t -> IR.Typ.t -> IBase.Location.t -> t -> t
val write_id : IR.Ident.t -> (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> t -> t
val write_field : IBase.Location.t -> ref:(Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> IR.Fieldname.t -> obj:(Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> t -> t Pulselib.PulseDomainInterface.AccessResult.t

write the edge ref --.field--> obj

val write_deref_field : IBase.Location.t -> ref:(Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> IR.Fieldname.t -> obj:(Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> t -> t Pulselib.PulseDomainInterface.AccessResult.t

write the edge ref --.field--> _ --*--> obj

val write_arr_index : IBase.Location.t -> ref:(Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> index:Pulselib.PulseBasicInterface.AbstractValue.t -> obj:(Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> t -> t Pulselib.PulseDomainInterface.AccessResult.t

write the edge ref[index]--> obj

val write_deref : IBase.Location.t -> ref:(Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> obj:(Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> t -> t Pulselib.PulseDomainInterface.AccessResult.t

write the edge ref --*--> obj

val write_deref_biad_isl : IBase.Location.t -> ref:(Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> Pulselib.PulseBasicInterface.AbstractValue.t Absint.HilExp.Access.t -> obj:(Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> t -> t Pulselib.PulseDomainInterface.AccessResult.t list
type invalidation_access =
| MemoryAccess of {
pointer : Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t;
access : Pulselib.PulseDomainInterface.BaseMemory.Access.t;
hist_obj_default : Pulselib.PulseBasicInterface.ValueHistory.t;
}

the value was read from the heap following the access edge at address pointer

| StackAddress of IR.Var.t * Pulselib.PulseBasicInterface.ValueHistory.t

the value was read from the stack

| UntraceableAccess

we don't know where the value came from; avoid using if possible

the way that was used to get to the invalidated address in the state; this is used to record the invalidation point in its history in addition to inside the Invalid attribute

val invalidate : invalidation_access -> IBase.Location.t -> Pulselib.PulseBasicInterface.Invalidation.t -> (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> t -> t Pulselib.PulseDomainInterface.AccessResult.t

record that the address is invalid

val invalidate_biad_isl : IBase.Location.t -> Pulselib.PulseBasicInterface.Invalidation.t -> (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> t -> t Pulselib.PulseDomainInterface.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 : IR.Procname.t -> IBase.Location.t -> (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> t -> t
val add_dynamic_type : IR.Typ.t -> Pulselib.PulseBasicInterface.AbstractValue.t -> t -> t
val remove_allocation_attr : Pulselib.PulseBasicInterface.AbstractValue.t -> t -> t
val invalidate_access : IBase.Location.t -> Pulselib.PulseBasicInterface.Invalidation.t -> (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> Pulselib.PulseDomainInterface.BaseMemory.Access.t -> t -> t Pulselib.PulseDomainInterface.AccessResult.t

record that what the address points via the access to is invalid

val invalidate_deref_access : IBase.Location.t -> Pulselib.PulseBasicInterface.Invalidation.t -> (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> Pulselib.PulseDomainInterface.BaseMemory.Access.t -> t -> t Pulselib.PulseDomainInterface.AccessResult.t

Like invalidate_access but invalidates dereferenced address.

val invalidate_array_elements : IBase.Location.t -> Pulselib.PulseBasicInterface.Invalidation.t -> (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> t -> t Pulselib.PulseDomainInterface.AccessResult.t

record that all the array elements that address points to is invalid

val shallow_copy : IBase.Location.t -> (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> t -> (t * (Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t)) Pulselib.PulseDomainInterface.AccessResult.t

returns the address of a new cell with the same edges as the original

val get_dynamic_type_unreachable_values : IR.Var.t list -> t -> (IR.Var.t * IR.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 : IR.Var.t list -> IBase.Location.t -> t -> t
val check_address_escape : IBase.Location.t -> IR.Procdesc.t -> Pulselib.PulseBasicInterface.AbstractValue.t -> Pulselib.PulseBasicInterface.ValueHistory.t -> t -> t Pulselib.PulseDomainInterface.AccessResult.t
val get_captured_actuals : IBase.Location.t -> captured_vars:(IR.Var.t * IR.CapturedVar.capture_mode * IR.Typ.t) list -> actual_closure:(Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) -> t -> (t * (IR.Var.t * ((Pulselib.PulseBasicInterface.AbstractValue.t * Pulselib.PulseBasicInterface.ValueHistory.t) * IR.Typ.t)) list) Pulselib.PulseDomainInterface.AccessResult.t