Overflow_checks.MakeSourceThis functor adds overflow checks to bitvector operations. I.E. for a biadd with ~size=32 it first performs the addition on 33 bits, then checks if the result fits in 32 bits (Checking signedness according to the various flags). Similarly, it adds guards to bisub, bimul, and bisdiv (dividing min_int by -1 underflows). There are no overflow guards on shifts as of yet.
If not, then it assume that it does fit, raising Sig.Bottom if the overflow is guaranteed.
It can also optionaly raise an alarm when a possible overflow is detected.
Specifically:
Binary_Forward.biadd ~size ~nsw:true and Binary_Forward.bisub ~size ~nsw:true now check then assume that their results (interpreted as signed) is in range [-2^{size-1} .. 2^{size-1}-1] (using signed comparison Binary_Forward.bisle)Binary_Forward.biadd ~size ~nuw:true and Binary_Forward.bisub ~size ~nuw:true now check then assume that their results (interpreted as unsigned) is smaller than [2^{size}-1] (using unsigned comparison Binary_Forward.biule)Binary_Forward.biadd ~size ~nusw:true and Binary_Forward.bisub ~size ~nusw:true now check then assume that their results (where left argument is unsigned, right argument is signed) is in range [0 .. 2^{size}-1] (fits unsigned result). This flag is assumed to be mutually exclusive with the two previous ones.module Sub : Sig.BASE_WITH_INTEGERinclude Sig.BASE
with type boolean = Sub.boolean
with type binary = Sub.binary
with type enum = Sub.enuminclude Sig.Minimal with type boolean = Sub.booleaninclude Sig.Minimal_No_Boolean with type boolean = Sub.booleaninclude Sig.With_Contextval root_context : unit -> Context.tOpens a new context, corresponding to the initial scope.
val context_pretty : Format.formatter -> Context.t -> unitDumps what is known about the current context: useful for debugging.
type boolean = Sub.booleanGuards
Joining variables together.
include Sig.With_Nondet with module Context := Contextval typed_nondet2 :
Context.t ->
Context.t ->
'a Context.in_tuple ->
Context.t * 'a Context.out_tupleThis joins two basic blocks and returns a new basic block. The Context.in_tuple and Context.out_tuple corresponds to the phi operations in SSA.
val nondet_same_context :
Context.t ->
'a Context.in_tuple ->
'a Context.out_tupleAdditionally, one may compute a non-deterministic choice between two values in the same basic block
It can be seen as equivalent as calling typed_nondet2 by passing the same context twice, which would return the same context.
Fixpoint computation.
include Sig.With_Fixpoint_Computation with module Context := ContextOpening a new context can also be seen as opening a new scope: new variables can be introduced, but variables of the parent scope can still be seen.
val typed_fixpoint_step :
iteration:int ->
init:Context.t ->
arg:Context.t ->
body:Context.t ->
(bool * 'a Context.in_tuple) ->
bool * (close:bool -> 'a Context.out_tuple * Context.t)Fixpoint step is a combination of inclusion checking + widening.
Also takes a boolean and a tuple of values which is the result of the evaluation of the body (the end of the loop).
Internally, it stores the arguments of the mu.
val widened_fixpoint_step :
widening_id:Sig.Widening_Id.t ->
previous:Context.t ->
next:Context.t ->
(bool * 'a Context.in_tuple) ->
Context.t * bool * 'a Context.out_tuplewidened_fixpoint_step ~previous ~next (bool,in_tuple) where:
widening_id is a unique representation of the widening point;previous is the previous domain state;next is the next domain state obtained after execution of the function body;bool is false if we know that the fixpoint is not reached yet, and true otherwise;in_tuple is the argument of the SSA phi function;returns a triple (context,bool,out_tuple) where:
context is the new domain state;bool is true if the fixpoint is reached, and false if not reached or we don't know;out_tuple is the result of the SSA phi function.The boolean domain should be present everywhere, as we need it or guards.
include Sig.With_Boolean
with module Context := Context
and type boolean := booleanval boolean_pretty : Context.t -> Format.formatter -> boolean -> unitval serialize_boolean :
Context.t ->
boolean ->
Context.t ->
boolean ->
'a Context.in_acc ->
(boolean, 'a) Context.resultEmpty denotes that the concretization has no value (or it is the concrete value representing the absence of value). Note that this does not necessarily imply that some error occured; for instance the offset of an uninitialized pointer can be represented with empty. Emptyness testing is a simple way of communicating between domains.
module Boolean_Forward :
Operator.BOOLEAN_FORWARD
with module Arity := Sig.Context_Arity_Forward(Context)
and type boolean := booleanval query_boolean : Context.t -> boolean -> Lattices.Quadrivalent.ttype binary = Sub.binarytype enum = Sub.enuminclude Sig.With_Types with module Context := Context and type binary := binaryval binary_unknown_typed :
size:Units.In_bits.t ->
Context.t ->
Types.TypedC.typ ->
binaryReturns an unknown value with a given type.
include Sig.With_Binary
with module Context := Context
and type binary := binary
and type boolean := booleanval binary_pretty :
size:Units.In_bits.t ->
Context.t ->
Format.formatter ->
binary ->
unitval serialize_binary :
widens:bool ->
size:Units.In_bits.t ->
Context.t ->
binary ->
Context.t ->
binary ->
'a Context.in_acc ->
(binary, 'a) Context.resultval binary_empty : size:Units.In_bits.t -> Context.t -> binaryval binary_unknown : size:Units.In_bits.t -> Context.t -> binaryinclude Sig.With_Binary_Forward
with module Context := Context
and type binary := binary
and type boolean := booleanmodule Binary_Forward :
Operator.BINARY_FORWARD
with module Arity := Sig.Context_Arity_Forward(Context)
and type boolean := boolean
and type binary := binaryinclude Sig.With_Enum
with module Context := Context
and type enum := enum
and type boolean := booleanval enum_pretty : Context.t -> Format.formatter -> enum -> unitval serialize_enum :
Context.t ->
enum ->
Context.t ->
enum ->
'a Context.in_acc ->
(enum, 'a) Context.resultinclude Sig.With_Enum_Forward
with module Context := Context
and type enum := enum
and type boolean := booleanmodule Enum_Forward :
Operator.ENUM_FORWARD
with module Arity := Sig.Context_Arity_Forward(Context)
and type boolean := boolean
and type enum := enumval union :
Operator.Condition.t ->
Context.t ->
'a Context.in_tuple ->
'a Context.out_tupleSet operations. Note that we do not distinguish binary from binary sets. Note that union reuses the serialize machinery.
val satisfiable : Context.t -> boolean -> Smtbackend.Smtlib_sig.satCheck if an assertion is satisfiable (i.e. a trace exists that makes it true).
include Sig.With_Integer
with module Context := Context
and type boolean := boolean
with type integer = Sub.integertype integer = Sub.integerCan return true if provably empty; false is always safe.
val integer_pretty : Context.t -> Format.formatter -> integer -> unitval serialize_integer :
widens:bool ->
Context.t ->
integer ->
Context.t ->
integer ->
'a Context.in_acc ->
(integer, 'a) Context.resultmodule Integer_Forward :
Operator.INTEGER_FORWARD
with module Arity := Sig.Context_Arity_Forward(Context)
and type boolean := boolean
and type integer := integermodule Integer_Query :
Sig.Integer_Query
with type abstract_state := Context.t
and type integer := integer