From 014fffbd7a4cd4ff27c1239f98116fb9f1b26f2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr> Date: Mon, 24 Feb 2020 10:42:16 +0100 Subject: [PATCH] [Eva] Comments the Domain_builder.Restrict functor and Domain_mode signature. --- src/plugins/value/domains/domain_builder.ml | 42 +++++++++++++++++++- src/plugins/value/domains/domain_builder.mli | 5 +++ src/plugins/value/domains/domain_mode.mli | 18 ++++++++- 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/plugins/value/domains/domain_builder.ml b/src/plugins/value/domains/domain_builder.ml index 876e52a7428..36683d88b7a 100644 --- a/src/plugins/value/domains/domain_builder.ml +++ b/src/plugins/value/domains/domain_builder.ml @@ -262,6 +262,7 @@ module Restrict open Domain_mode + (* Defines the join and the narrow of different modes. *) module Mode = struct include Mode @@ -277,11 +278,19 @@ module Restrict let narrow = merge (||) end + (* Map that binds functions to their analysis mode. *) let functions_map = List.fold_left (fun map (kf, mode) -> Kernel_function.Map.add kf mode map) Kernel_function.Map.empty Scope.functions + (* This module propagates states of type [(state * mode) option]: + - None is propagated as long as no functions from [Scope.functions] + is analyzed. + - then the current [mode] is propagated alongside the state. Queries and + transfer functions are applied accordingly. The current mode is replaced + at function calls by [mode.calls]. *) + module Info = struct let module_name = Domain.name ^ " restricted" end module D = Datatype.Pair_with_collections (Domain) (Mode) (Info) @@ -301,6 +310,9 @@ module Restrict | None -> Domain.top | Some (state, _mode) -> state + (* When the first function from [Scope.functions] is encountered, starts the + analysis with the state computed by this function. It is an empty state in + which the global variables exist and may have any values. *) let compute_starting_state () = let empty = Domain.empty () in let var_kind = Abstract_domain.Global in @@ -310,6 +322,8 @@ module Restrict in Globals.Vars.fold init empty + (* Do not recompute each time the starting state. Do not compute the starting + state too early either, in case it depends on analysis options. *) let get_starting_state = let starting_state = ref None in fun () -> @@ -347,8 +361,8 @@ module Restrict (* ----- Queries ---------------------------------------------------------- *) - let default_query = `Value (Value.top, None), Alarmset.all - + (* Applies the [query] only if the current mode allows the domain to read. + Otherwise, returns [default]. *) let make_query default query = function | None -> default | Some (state, mode) -> @@ -356,6 +370,8 @@ module Restrict then query state else default + let default_query = `Value (Value.top, None), Alarmset.all + let extract_expr oracle state expr = make_query default_query (fun s -> Domain.extract_expr oracle s expr) state @@ -376,6 +392,8 @@ module Restrict (* ----- Transfer functions ----------------------------------------------- *) + (* Applies the transfer function [f] only if the current mode allows the + domain to write. Otherwise, returns the state unchanged. *) let make_transfer f = function | None -> `Value None | Some (state, mode) -> @@ -387,6 +405,9 @@ module Restrict let assume stmt expr positive valuation = make_transfer (Domain.assume stmt expr positive valuation) + (* Applies the [assign] transfer function according to the current mode. + In any case, removes from the state the properties depending on the memory + location modified by the assignment. *) let assign kinstr lvalue expr assigned valuation = function | None -> `Value None | Some (state, mode) -> @@ -398,6 +419,10 @@ module Restrict let state = Domain.logic_assign None lvalue.lloc state in `Value (Some (state, mode)) + (* Starts an analysis at call [call] with state [state]. The domain was not + enabled before this call: the concrete arguments may contain variables that + have never been introduced into the state, so we should not use them. This + function only introduce the formal parameters in the state. *) let start_analysis call state = let formals = List.map (fun argument -> argument.formal) call.arguments in let kind = Abstract_domain.Formal call.kf in @@ -406,7 +431,16 @@ module Restrict let state = List.fold_left initialize state formals in state + (* When interpreting a function call: + - if the mode of the function called allows the domain to infer properties, + use [start_call] and [finalize_call] as normal. If the current mode did + not allow the domain to infer properties, use [start_analysis] instead. + - otherwise, only propagate the state from the call site to kill the + properties that depend on locations written in the called functions. *) + let start_call stmt call valuation state = + (* Starts the call with mode [new_mode]. [previous_mode] is the current mode + of the caller. *) let start_call_with_mode ?previous_mode ~new_mode state = if new_mode.current.write then @@ -418,6 +452,9 @@ module Restrict `Value (Some (start_analysis call state, new_mode)) else `Value (Some (state, new_mode)) in + (* If an analysis mode is defined for the called function in [Scope], + then this mode becomes the new current mode. Otherwise, use the [calls] + field of the previous mode. *) let called_mode = Kernel_function.Map.find_opt call.kf functions_map in match state, called_mode with | Some (state, previous_mode), Some new_mode -> @@ -483,6 +520,7 @@ module Restrict let enter_scope kind varinfos = lift (Domain.enter_scope kind varinfos) let leave_scope kf varinfos = lift (Domain.leave_scope kf varinfos) + (* Uses the mode of the 'main' function to start the analysis. *) let empty () = let main_kf = fst (Globals.entry_point ()) in match Kernel_function.Map.find_opt main_kf functions_map with diff --git a/src/plugins/value/domains/domain_builder.mli b/src/plugins/value/domains/domain_builder.mli index 718c0c5febd..66613b44d54 100644 --- a/src/plugins/value/domains/domain_builder.mli +++ b/src/plugins/value/domains/domain_builder.mli @@ -56,6 +56,11 @@ module Complete_Simple_Cvalue and type location = Precise_locs.precise_location and type state = Domain.t +(* Restricts an abstract domain on specific functions. The domain will only be + enabled on the given functions. Moreover, a mode is associated to each of + these functions, allowing (or not) the domain to infer or use properties + in the current function and in all functions called from it. + See {!Domain_mode} for more details. *) module Restrict (Value: Abstract_value.S) (Domain: Abstract.Domain.Internal with type value = Value.t) diff --git a/src/plugins/value/domains/domain_mode.mli b/src/plugins/value/domains/domain_mode.mli index 96a2c64b69a..050aa6e4147 100644 --- a/src/plugins/value/domains/domain_mode.mli +++ b/src/plugins/value/domains/domain_mode.mli @@ -20,14 +20,30 @@ (* *) (**************************************************************************) +(** This module defines the mode to restrict an abstract domains on specific + functions. *) + +(** Permission for an abstract domain to read/write its state. + If [write] is true, the domain infers new properties when interpreting + assignments, assumptions, and logical assertions. Otherwise, it only + propagates already known properties as long as they hold. + If [read] is true, the domain uses its inferred properties to improve + the evaluation of expressions by extracting information from its state. + It can also evaluate logical assertions. *) type permission = { read: bool; write: bool; } + +(** Mode for the analysis of a function [f]: + - [current] is the read/write permission for [f]. + - [calls] is the read/write permission for all functions called from [f]. *) type mode = { current: permission; calls: permission; } +(** Datatype for modes. *) module Mode : sig include Datatype.S_with_collections with type t = mode - val all: t + val all: t (** Default mode: all permissions are granted. *) end +(** A function associated with an analysis mode. *) type function_mode = Kernel_function.t * mode module Function_Mode: -- GitLab