Module Overflow_checks.Make
This 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:trueandBinary_Forward.bisub ~size ~nsw:truenow check thenassumethat their results (interpreted as signed) is in range[-2^{size-1} .. 2^{size-1}-1](using signed comparisonBinary_Forward.bisle)Binary_Forward.biadd ~size ~nuw:trueandBinary_Forward.bisub ~size ~nuw:truenow check thenassumethat their results (interpreted as unsigned) is smaller than[2^{size}-1](using unsigned comparisonBinary_Forward.biule)Binary_Forward.biadd ~size ~nusw:trueandBinary_Forward.bisub ~size ~nusw:truenow check thenassumethat 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.
Parameters
module Sub : Sig.BASE_WITH_INTEGERSignature
include Sig.BASE
with type boolean = Sub.boolean
with type binary = Sub.binary
with type enum = Sub.enum
include Sig.Minimal with type boolean = Sub.boolean
include Sig.Minimal_No_Boolean with type boolean = Sub.boolean
include Sig.With_Context
module Context : Sig.Contextval root_context : unit -> Context.tOpens a new context, corresponding to the initial scope.
val context_pretty : Stdlib.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 := Context
val 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 := Context
Opening 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_idis a unique representation of the widening point;previousis the previous domain state;nextis the next domain state obtained after execution of the function body;boolis false if we know that the fixpoint is not reached yet, and true otherwise;in_tupleis the argument of the SSA phi function;
returns a triple (context,bool,out_tuple) where:
contextis the new domain state;boolis true if the fixpoint is reached, and false if not reached or we don't know;out_tupleis 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 := boolean
module Boolean : Datatype_sig.S with type t = booleanval 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 := binary
val 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 := boolean
module Binary : Datatype_sig.S with type t = binaryval binary_pretty :
size:Units.In_bits.t ->
Context.t ->
Stdlib.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 := boolean
module 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 := boolean
module Enum : Datatype_sig.S with type t = enumval 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 := boolean
module 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.integer
type integer = Sub.integermodule Integer : Datatype_sig.S with type t = integerCan return true if provably empty; false is always safe.
val 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