Skip to content
Snippets Groups Projects
Eva.mli 17.7 KiB
Newer Older
(** Eva public API.

   The main modules are:
   - Analysis: run the analysis.
   - Results: access analysis results, especially the values of expressions
      and memory locations of lvalues at each program point.

   The following modules allow configuring the Eva analysis:
   - Value_parameters: change the configuration of the analysis.
   - Eva_annotations: add local annotations to guide the analysis.
   - Builtins: register ocaml builtins to be used by the cvalue domain
       instead of analysing the body of some C functions.

   Other modules are for internal use only. *)

(* This file is generated. Do not edit. *)

module Analysis: sig
  val compute : unit -> unit
  (** Computes the Eva analysis, if not already computed, using the entry point
      of the current project. You may set it with {!Globals.set_entry_point}.
      @raise Globals.No_such_entry_point if the entry point is incorrect
      @raise Db.Value.Incorrect_number_of_arguments if some arguments are
      specified for the entry point using {!Db.Value.fun_set_args}, and
      an incorrect number of them is given.
      @plugin development guide *)
  val is_computed : unit -> bool
  (** Return [true] iff the Eva analysis has been done. *)
  val self : State.t
  (** Internal state of Eva analysis from projects viewpoint. *)
module Results: sig
  (** Eva's result API is a work-in-progress interface to allow accessing the
      analysis results once its completed. It is experimental and is very likely
      to change in the future. It aims at replacing [Db.Value] but does not
      completely covers all its usages yet. As for now, this interface has some
      advantages over Db's :
      - evaluations uses every available domains and not only Cvalue;
      - the caller may distinguish failure cases when a request is unsucessful;
      - working with callstacks is easy;
      - some common shortcuts are provided (e.g. for extracting ival directly);
      - overall, individual functions are simpler.
      The idea behind this API is that requests must be decomposed in several
      steps. For instance, to evaluate an expression :
      1. first, you have to state where you want to evaluate it,
      2. optionally, you may specify in which callstack,
      3. you choose the expression to evaluate,
      4. you require a destination type to evaluate into.
      Usage sketch :
      Eva.Results.(
        before stmt |> in_callstack cs |>
        eval_var vi |> as_int |> default 0)
      or equivalently, if you prefer
      Eva.Results.(
        default O (as_int (eval_var vi (in_callstack cs (before stmt))))
  type callstack = (Cil_types.kernel_function * Cil_types.kinstr) list
  type value
  type address
  type 'a evaluation
  type error = Bottom | Top | DisabledDomain
  type 'a result = ('a,error) Result.t
  (** Results handling *)
  (** Translates an error to a human readable string. *)
  val string_of_error : error -> string
  (** Pretty printer for errors. *)
  val pretty_error : Format.formatter -> error -> unit
  (** Pretty printer for API's results. *)
  val pretty_result : (Format.formatter -> 'a -> unit) ->
    Format.formatter -> 'a result -> unit
  (** [default d r] extracts the value of [r] if [r] is Ok,
      or use the default value [d] otherwise.
      Equivalent to [Result.value ~default:d r] *)
  val default : 'a -> 'a result -> 'a
  (** Control point selection *)
  (** At the start of the analysis, but after the initialization of globals. *)
  val at_start : request
  (** At the end of the analysis, after the main function has returned. *)
  val at_end : request
  (** At the start of the given function. *)
  val at_start_of : Cil_types.kernel_function -> request
  (** At the end of the given function. *)
  val at_end_of : Cil_types.kernel_function -> request
  (** Just before a statement is executed. *)
  val before : Cil_types.stmt -> request
  (** Just after a statement is executed. *)
  val after : Cil_types.stmt -> request
  (** Just before a statement or at the start of the analysis. *)
  val before_kinstr : Cil_types.kinstr -> request
  (** Callstack selection *)
  (** Only consider the given callstack.
      Replaces previous calls to [in_callstack] or [in_callstacks]. *)
  val in_callstack : callstack -> request -> request
  (** Only consider the callstacks from the given list.
      Replaces previous calls to [in_callstack] or [in_callstacks]. *)
  val in_callstacks : callstack list -> request -> request
  (** Only consider callstacks satisfying the given predicate. Several filters
      can be added. If callstacks are also selected with [in_callstack] or
      [in_callstacks], only the selected callstacks will be filtered. *)
  val filter_callstack : (callstack -> bool) -> request -> request
  (** Working with callstacks *)
  (** Returns the list of reachable callstacks from the given request. *)
  val callstacks : request -> callstack list
  (** Returns a list of subrequests for each reachable callstack from
      the given request. *)
  val by_callstack : request -> (callstack * request) list
  (** Iterates on the reachable callstacks from the request. *)
  val iter_callstacks : (callstack -> request -> unit) -> request -> unit
  (** Folds on the reachable callstacks from the request. *)
  val fold_callstacks : (callstack -> request -> 'a -> 'a) -> 'a -> request -> 'a
  (** State requests *)
  (** Returns the list of expressions which have been inferred to be equal to
      the given expression by the Equality domain. *)
  val equality_class : Cil_types.exp -> request -> Cil_types.exp list result
  (** Returns the Cvalue model. *)
  val as_cvalue_model : request -> Cvalue.Model.t result
  (** Dependencies *)
  (** Computes (an overapproximation of) the memory zones that must be read to
      evaluate the given expression, including all adresses computations. *)
  val expr_deps : Cil_types.exp -> request -> Locations.Zone.t
  (** Computes (an overapproximation of) the memory zones that must be read to
      evaluate the given lvalue, including the lvalue zone itself. *)
  val lval_deps : Cil_types.lval -> request -> Locations.Zone.t
  (** Computes (an overapproximation of) the memory zones that must be read to
      evaluate the given lvalue, excluding the lvalue zone itself. *)
  val address_deps : Cil_types.lval -> request -> Locations.Zone.t
  (** Evaluation *)
  (** Returns (an overapproximation of) the possible values of the variable. *)
  val eval_var : Cil_types.varinfo -> request -> value evaluation
  (** Returns (an overapproximation of) the possible values of the lvalue. *)
  val eval_lval : Cil_types.lval -> request -> value evaluation
  (** Returns (an overapproximation of) the possible values of the expression. *)
  val eval_exp : Cil_types.exp -> request -> value evaluation
  (** Returns (an overapproximation of) the possible addresses of the lvalue. *)
  val eval_address : Cil_types.lval -> request -> address evaluation
  (** Returns the kernel functions into which the given expression may evaluate.
      If the callee expression doesn't always evaluate to a function, those
      spurious values are ignored. If it always evaluate to a non-function value
      then the returned list is empty.
      Raises [Stdlib.Invalid_argument] if the callee expression is not an lvalue
      without offset.
      Also see [callee] for a function which applies directly on Call
      statements. *)
  val eval_callee : Cil_types.exp -> request -> Kernel_function.t list result
  (** Evaluated values conversion *)
  (** In all functions below, if the abstract value inferred by Eva does not fit
      in the required type, [Error Top] is returned, as Top is the only possible
      over-approximation of the request. *)
  (** Converts the value into a singleton ocaml int. *)
  val as_int : value evaluation -> int result
  (** Converts the value into a singleton unbounded integer. *)
  val as_integer : value evaluation -> Integer.t result
  (** Converts the value into a floating point number. *)
  val as_float : value evaluation -> float result
  (** Converts the value into a C number abstraction. *)
  val as_ival : value evaluation -> Ival.t result
  (** Converts the value into a floating point abstraction. *)
  val as_fval : value evaluation -> Fval.t result
  (** Converts the value into a Cvalue abstraction. *)
  val as_cvalue : value evaluation -> Cvalue.V.t result
  (** Converts into a C location abstraction. *)
  val as_location : address evaluation -> Locations.location result
  (** Converts into a Zone. Error cases are converted into bottom or top zones
      accordingly. *)
  val as_zone: ?access:Locations.access -> address evaluation ->
    Locations.Zone.t
  (** Converts into a Zone result. *)
  val as_zone_result : ?access:Locations.access -> address evaluation ->
  (** Evaluation properties *)
  (** Returns whether the evaluated value is initialized or not. If the value have
      been evaluated from a Cil expression, it is always initialized. *)
  val is_initialized : value evaluation -> bool
  (** Returns the set of alarms emitted during the evaluation. *)
  val alarms : 'a evaluation -> Alarms.t list
  (** Reachability *)
  (** Returns true if there are no reachable states for the given request. *)
  val is_empty : request -> bool
  (** Returns true if an evaluation leads to bottom, i.e. if the given expression
      or lvalue cannot be evaluated to a valid result for the given request. *)
  val is_bottom : 'a evaluation -> bool
  (** Returns true if the function has been analyzed. *)
  val is_called : Cil_types.kernel_function -> bool
  (** Returns true if the statement has been reached by the analysis. *)
  val is_reachable : Cil_types.stmt -> bool
  (** Returns true if the statement has been reached by the analysis, or if
      the main function has been analyzed for [Kglobal]. *)
  val is_reachable_kinstr : Cil_types.kinstr -> bool
  (*** Callers / Callees / Callsites *)
  (** Returns the list of inferred callers of the given function. *)
  val callers : Cil_types.kernel_function -> Cil_types.kernel_function list
  (** Returns the list of inferred callers, and for each of them, the list
      of callsites (the call statements) inside. *)
  val callsites : Cil_types.kernel_function ->
    (Cil_types.kernel_function * Cil_types.stmt list) list
  (** Returns the kernel functions called in the given statement.
      If the callee expression doesn't always evaluate to a function, those
      spurious values are ignored. If it always evaluate to a non-function value
      then the returned list is empty.
      Raises [Stdlib.Invalid_argument] if the statement is not a [Call]
      instruction or a [Local_init] with [ConsInit] initializer. *)
  val callee : Cil_types.stmt -> Kernel_function.t list
  (** Configuration of the analysis. *)

  (** Returns the list (name, descr) of currently enabled abstract domains. *)
  val enabled_domains: unit -> (string * string) list
  (** [use_builtin kf name] instructs the analysis to use the builtin [name]
      to interpret calls to function [kf].
      Raises [Not_found] if there is no builtin of name [name]. *)
  val use_builtin: Cil_types.kernel_function -> string -> unit
  (** [use_global_value_partitioning vi] instructs the analysis to use
      value partitioning on the global variable [vi]. *)
  val use_global_value_partitioning: Cil_types.varinfo -> unit
module Eva_annotations: sig
  (** Register special annotations to locally guide the Eva analysis:
      - slevel annotations: "slevel default", "slevel merge" and "slevel i"
      - loop unroll annotations: "loop unroll term"
      - value partitioning annotations: "split term" and "merge term"
      - subdivision annotations: "subdivide i"
  (** Annotations tweaking the behavior of the -eva-slevel parameter. *)
  type slevel_annotation =
    | SlevelMerge        (** Join all states separated by slevel. *)
    | SlevelDefault      (** Use the limit defined by -eva-slevel. *)
    | SlevelLocal of int (** Use the given limit instead of -eva-slevel. *)
    | SlevelFull         (** Remove the limit of number of separated states. *)
  type unroll_annotation =
    | UnrollAmount of Cil_types.term (** Unroll the n first iterations. *)
    | UnrollFull (** Unroll amount defined by -eva-default-loop-unroll. *)
  type split_kind = Static | Dynamic
  type split_term =
    | Expression of Cil_types.exp
    | Predicate of Cil_types.predicate
  (** Split/merge annotations for value partitioning.  *)
  type flow_annotation =
    | FlowSplit of split_term * split_kind
    (** Split states according to a term. *)
    | FlowMerge of split_term
    (** Merge states separated by a previous split. *)
  type allocation_kind = By_stack | Fresh | Fresh_weak | Imprecise
  val get_slevel_annot : Cil_types.stmt -> slevel_annotation option
  val get_unroll_annot : Cil_types.stmt -> unroll_annotation list
  val get_flow_annot : Cil_types.stmt -> flow_annotation list
  val get_subdivision_annot : Cil_types.stmt -> int list
  val get_allocation: Cil_types.stmt -> allocation_kind
  val add_slevel_annot : emitter:Emitter.t ->
    Cil_types.stmt -> slevel_annotation -> unit
  val add_unroll_annot : emitter:Emitter.t ->
    Cil_types.stmt -> unroll_annotation -> unit
  val add_flow_annot : emitter:Emitter.t ->
    Cil_types.stmt -> flow_annotation -> unit
  val add_subdivision_annot : emitter:Emitter.t ->
    Cil_types.stmt -> int -> unit
end
module Eval: sig
  (** Can the results of a function call be cached with memexec? *)
  type cacheable =
    | Cacheable      (** Functions whose result can be safely cached. *)
    | NoCache        (** Functions whose result should not be cached, but for
                         which the caller can still be cached. Typically,
                         functions printing something during the analysis. *)
    | NoCacheCallers (** Functions for which neither the call, neither the
                         callers, can be cached. *)
  (** Eva analysis builtins for the cvalue domain, more efficient than their
      equivalent in C. *)
  exception Invalid_nb_of_args of int
  exception Outside_builtin_possibilities
  (* Signature of a builtin: type of the result, and type of the arguments. *)
  type builtin_type = unit -> typ * typ list
  (** Can the results of a builtin be cached? See {eval.mli} for more details.*)
  type cacheable = Eval.cacheable = Cacheable | NoCache | NoCacheCallers
  type full_result = {
    c_values: (Cvalue.V.t option * Cvalue.Model.t) list;
    (** A list of results, consisting of:
        - the value returned (ie. what is after the 'return' C keyword)
        - the memory state after the function has been executed. *)
    (** An over-approximation of the bases in which addresses of local variables
        might have been written *)
    c_from: (Function_Froms.froms * Locations.Zone.t) option;
    (** If not None, the froms of the function, and its sure outputs;
        i.e. the dependencies of the result and of each zone written to. *)
  (** The result of a builtin can be given in different forms. *)
  type call_result =
    | States of Cvalue.Model.t list
    (** A disjunctive list of post-states at the end of the C function.
        Can only be used if the C function does not write the address of local
        variables, does not read other locations than the call arguments, and
        does not write other locations than the result. *)
    (** A disjunctive list of resulting values. The specification is used to
        compute the post-state, in which the result is replaced by the values
        computed by the builtin. *)
    (** See [full_result] type. *)
  (** Type of a cvalue builtin, whose arguments are:
      - the memory state at the beginning of the function call;
      - the list of arguments of the function call. *)
  type builtin = Cvalue.Model.t -> (exp * Cvalue.V.t) list -> call_result
  (** [register_builtin name ?replace ?typ cacheable f] registers the function [f]
      as a builtin to be used instead of the C function of name [name].
      If [replace] is provided, the builtin is also used instead of the C function
      of name [replace], unless option -eva-builtin-auto is disabled.
      If [typ] is provided, consistency between the expected [typ] and the type of
      the C function is checked before using the builtin.
      The results of the builtin are cached according to [cacheable]. *)
    string -> ?replace:string -> ?typ:builtin_type -> cacheable -> builtin -> unit
  (** Has a builtin been registered with the given name? *)

module Eval_terms: sig
  (** [annot_predicate_deps ~pre ~here p] computes the logic dependencies needed
      to evaluate the predicate [p] in a code annotation in cvalue state [here],
      in a function whose pre-state is [pre].
      Returns None on either an evaluation error or on unsupported construct. *)
  val annot_predicate_deps:
    pre:Cvalue.Model.t -> here:Cvalue.Model.t ->
    Cil_types.predicate -> Locations.Zone.t option
end

module Value_results: sig
  type results

  val get_results: unit -> results
  val set_results: results -> unit
  val merge: results -> results -> results
  val change_callstacks:
    (Value_types.callstack -> Value_types.callstack) -> results -> results
  (** Change the callstacks for the results for which this is meaningful.
      For technical reasons, the top of the callstack must currently
      be preserved. *)
end

module Unit_tests: sig
  (** Currently tested by this module:
      - semantics of sign values. *)

  (** Runs some programmatic tests on Eva. *)
  val run: unit -> unit
end