diff --git a/src/plugins/wp/Factory.ml b/src/plugins/wp/Factory.ml index 1daa6200a0dd9eaf3b14f28d4bde8f6ddb16db75..6d132c1ffac6028ce805bd04dcc89662631e0c27 100644 --- a/src/plugins/wp/Factory.ml +++ b/src/plugins/wp/Factory.ml @@ -24,7 +24,7 @@ (* --- Model Factory --- *) (* -------------------------------------------------------------------------- *) -type mheap = Hoare | ZeroAlias | Region | Typed of MemTyped.pointer | Value +type mheap = Hoare | ZeroAlias | Region | Typed of MemTyped.pointer | Eva1 | Eva2 type mvar = Raw | Var | Ref | Caveat type setup = { @@ -68,7 +68,8 @@ let descr_mheap d = function | ZeroAlias -> main d "zeroalias" | Hoare -> main d "hoare" | Typed p -> main d "typed" ; descr_mtyped d p - | Value -> main d "value" + | Eva1 -> main d "eva1" + | Eva2 -> main d "eva2" let descr_mvar d = function | Var -> () @@ -233,6 +234,8 @@ module Model_Typed_Var = Register(Var)(MemTyped) module Model_Typed_Ref = Register(Ref)(MemTyped) module Model_Caveat = Register(Caveat)(MemTyped) +module MemVal = MemVal.Make(MemVal.Eva) + module MakeCompiler(M:Sigs.Model) = struct module M = M module C = CodeSemantics.Make(M) @@ -249,6 +252,7 @@ module Comp_Typed_Var = MakeCompiler(Model_Typed_Var) module Comp_Typed_Ref = MakeCompiler(Model_Typed_Ref) module Comp_Caveat = MakeCompiler(Model_Caveat) module Comp_MemValue = MakeCompiler(MemValue) +module Comp_MemVal = MakeCompiler(MemVal) let compiler mheap mvar : (module Sigs.Compiler) = @@ -261,7 +265,8 @@ let compiler mheap mvar : (module Sigs.Compiler) = | Typed _ , Raw -> (module Comp_MemTyped) | Typed _ , Var -> (module Comp_Typed_Var) | Typed _ , Ref -> (module Comp_Typed_Ref) - | Value, _ -> (module Comp_MemValue) + | Eva1, _ -> (module Comp_MemVal) + | Eva2, _ -> (module Comp_MemValue) (* -------------------------------------------------------------------------- *) (* --- Tuning --- *) @@ -271,6 +276,8 @@ let configure_mheap = function | Hoare -> MemEmpty.configure () | ZeroAlias -> MemZeroAlias.configure () | Region -> MemRegion.configure () + | Eva1 -> MemVal.configure () + | Eva2 -> MemValue.configure () | Typed p -> let rollback_memtyped = MemTyped.configure () in let orig_memtyped_pointer = Context.push MemTyped.pointer p in @@ -279,7 +286,6 @@ let configure_mheap = function Context.pop MemTyped.pointer orig_memtyped_pointer in rollback - | Value -> MemValue.configure () let configure_driver setup driver () = let rollback_mheap = configure_mheap setup.mheap in @@ -341,6 +347,7 @@ let split ~warning (m:string) : string list = (fun c -> match c with | 'A' .. 'Z' -> Buffer.add_char buffer c + | '0' .. '9' -> Buffer.add_char buffer c | '_' | ',' | '@' | '+' | ' ' | '\t' | '\n' | '(' | ')' -> flush () | _ -> warning (Printf.sprintf "In model spec %S : unexpected character '%c'" m c) @@ -355,8 +362,9 @@ let update_config ~warning m s = function | "TYPED" -> { s with mheap = Typed MemTyped.Fits } | "CAST" -> { s with mheap = Typed MemTyped.Unsafe } | "NOCAST" -> { s with mheap = Typed MemTyped.NoCast } - | "VALUE" -> { s with mheap = Value } + | "EVA1" -> { s with mheap = Eva1 } | "CAVEAT" -> { s with mvar = Caveat } + | "EVA2" -> { s with mheap = Eva2 } | "RAW" -> { s with mvar = Raw } | "REF" -> { s with mvar = Ref } | "VAR" -> { s with mvar = Var } diff --git a/src/plugins/wp/Factory.mli b/src/plugins/wp/Factory.mli index d83156b90222fc88ff459e1ed050b6b301c00391..e2978a49031eda7227d6265330029b443124a1af 100644 --- a/src/plugins/wp/Factory.mli +++ b/src/plugins/wp/Factory.mli @@ -24,7 +24,7 @@ (* --- Model Factory --- *) (* -------------------------------------------------------------------------- *) -type mheap = Hoare | ZeroAlias | Region | Typed of MemTyped.pointer | Value +type mheap = Hoare | ZeroAlias | Region | Typed of MemTyped.pointer | Eva1 | Eva2 type mvar = Raw | Var | Ref | Caveat type setup = { diff --git a/src/plugins/wp/GuiPanel.ml b/src/plugins/wp/GuiPanel.ml index b0d649a340294ea268da139fc2722f1674585bf7..08a408271cfbe83e6a2c1ae57b7a332d01dc99e8 100644 --- a/src/plugins/wp/GuiPanel.ml +++ b/src/plugins/wp/GuiPanel.ml @@ -93,7 +93,7 @@ let run_and_prove (* --- Model Panel --- *) (* ------------------------------------------------------------------------ *) -type memory = TREE | HOARE | TYPED | REGION | VALUE +type memory = TREE | HOARE | TYPED | REGION | EVA1 | EVA2 class model_selector (main : Design.main_window_extension_points) = let dialog = new Wpane.dialog @@ -101,7 +101,8 @@ class model_selector (main : Design.main_window_extension_points) = let memory = new Widget.group HOARE in let r_hoare = memory#add_radio ~label:"Hoare Memory Model" ~value:HOARE () in let r_typed = memory#add_radio ~label:"Typed Memory Model" ~value:TYPED () in - let r_value = memory#add_radio ~label:"Value Memory Model" ~value:VALUE () in + let r_eva1 = memory#add_radio ~label:"Eva Memory Model 1" ~value:EVA1 () in + let r_eva2 = memory#add_radio ~label:"Eva Memory Model 2" ~value:EVA2 () in let c_casts = new Widget.checkbox ~label:"Unsafe casts" () in let c_byref = new Widget.checkbox ~label:"Reference Arguments" () in let c_ctxt = new Widget.checkbox ~label:"Context Arguments (Caveat)" () in @@ -114,7 +115,8 @@ class model_selector (main : Design.main_window_extension_points) = begin dialog#add_row r_hoare#coerce ; dialog#add_row r_typed#coerce ; - dialog#add_row r_value#coerce ; + dialog#add_row r_eva1#coerce ; + dialog#add_row r_eva2#coerce ; dialog#add_row c_casts#coerce ; dialog#add_row c_byref#coerce ; dialog#add_row c_ctxt#coerce ; @@ -142,7 +144,9 @@ class model_selector (main : Design.main_window_extension_points) = | Region -> memory#set REGION | Hoare -> memory#set HOARE | Typed m -> memory#set TYPED ; c_casts#set (m = MemTyped.Unsafe) - | Value -> memory#set VALUE) ; + | Eva1 -> memory#set EVA1 + | Eva2 -> memory#set EVA2 + ) ; c_byref#set (s.mvar = Ref) ; c_ctxt#set (s.mvar = Caveat) ; c_cint#set (s.cint = Cint.Machine) ; @@ -156,7 +160,8 @@ class model_selector (main : Design.main_window_extension_points) = | HOARE -> Hoare | TYPED -> Typed (if c_casts#get then MemTyped.Unsafe else MemTyped.Fits) - | VALUE -> Value + | EVA1 -> Eva1 + | EVA2 -> Eva2 in { mheap = m ; mvar = if c_ctxt#get then Caveat else if c_byref#get then Ref else Var ; diff --git a/src/plugins/wp/Makefile.in b/src/plugins/wp/Makefile.in index c662db3ead0e3afaf813507f870fc08aa5fa37d9..3f1baf9ef69166971f367aa0e72edd9fa9408a47 100644 --- a/src/plugins/wp/Makefile.in +++ b/src/plugins/wp/Makefile.in @@ -78,9 +78,9 @@ PLUGIN_CMO:= \ CodeSemantics \ LogicCompiler \ LogicSemantics LogicAssigns \ - Sigma MemLoader \ + Sigma MemLoader MemDebug \ MemEmpty MemZeroAlias MemVar \ - MemMemory MemTyped MemValue MemRegion \ + MemMemory MemTyped MemRegion MemValue MemVal \ wpReached wpRTE wpAnnot \ CfgCompiler StmtSemantics \ VCS script proof wpo wpReport \ @@ -242,7 +242,7 @@ WP_API_BASE= \ Plang.mli Pcfg.mli Pcond.mli \ CodeSemantics.mli \ LogicCompiler.mli LogicSemantics.mli \ - Sigma.mli MemVar.mli MemTyped.mli MemValue.mli \ + Sigma.mli MemVar.mli MemTyped.mli MemVal.mli MemValue.mli \ CfgCompiler.mli StmtSemantics.mli \ Factory.mli driver.mli VCS.mli Tactical.mli Strategy.mli Auto.mli \ VC.mli wpo.mli ProverTask.mli prover.mli diff --git a/src/plugins/wp/MemDebug.ml b/src/plugins/wp/MemDebug.ml new file mode 100644 index 0000000000000000000000000000000000000000..66ba6046881734285679f86b2086da17e071d770 --- /dev/null +++ b/src/plugins/wp/MemDebug.ml @@ -0,0 +1,273 @@ +(**************************************************************************) +(* *) +(* This file is part of WP plug-in of Frama-C. *) +(* *) +(* Copyright (C) 2007-2017 *) +(* CEA (Commissariat a l'energie atomique et aux energies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(* *) +(**************************************************************************) + +open Cil_datatype +open Lang.F +open Sigs + +(* ------------------------------------------------------------------------ *) +(* ---- Pretty-printers ---- *) +(* ------------------------------------------------------------------------ *) + +let pp_sequence pp_val fmt seq = + Format.fprintf fmt "@[{pre=%a,@,post=%a}@]" + pp_val seq.pre pp_val seq.post + +let pp_equation fmt = function + | Set (lt, rt) -> Format.fprintf fmt "@[%a =@, %a@]" pp_term lt pp_term rt + | Assert pred -> pp_pred fmt pred + +let pp_acs fmt = function + | RW -> Format.pp_print_string fmt "RW" + | RD -> Format.pp_print_string fmt "RD" + | OBJ -> Format.pp_print_string fmt "OBJ" + +let pp_value pp_loc fmt = function + | Val t -> pp_term fmt t + | Loc l -> pp_loc fmt l + +let pp_rloc pp_loc fmt = function + | Rloc(_obj,l) -> Format.fprintf fmt "[@{%a}@]" pp_loc l + | Rrange(l,_obj,tmin,tmax) -> + Format.fprintf fmt "@[%a+(%a..%a)@]" pp_loc l + (Pretty_utils.pp_opt pp_term) tmin (Pretty_utils.pp_opt pp_term) tmax + +let pp_sloc pp_loc fmt = function + | Sloc l -> Format.fprintf fmt "@[{%a}@]" pp_loc l + | Sarray(l,_obj,size) -> Format.fprintf fmt "@[%a+(0..%d)@]" pp_loc l size + | Srange(l,_obj,tmin,tmax) -> + Format.fprintf fmt "@[%a+(%a..%a)@]" pp_loc l + (Pretty_utils.pp_opt pp_term) tmin (Pretty_utils.pp_opt pp_term) tmax + | Sdescr(xs,l,p) -> + Format.fprintf fmt "@[{ %a @,| %a@,; %a }@]" pp_loc l + (Pretty_utils.pp_list pp_var) xs pp_pred p + +(* ------------------------------------------------------------------------ *) +(* ---- Debug Memory Model ---- *) +(* ------------------------------------------------------------------------ *) + +let dkey_cons = Wp_parameters.register_category "memdebug:cons" +let dkey_loc = Wp_parameters.register_category "memdebug:loc" +let dkey_cast = Wp_parameters.register_category "memdebug:cast" +let dkey_access = Wp_parameters.register_category "memdebug:access" +let dkey_valid = Wp_parameters.register_category "memdebug:valid" +let dkey_alias = Wp_parameters.register_category "memdebug:alias" + +let debug_cons = Wp_parameters.debug ~dkey:dkey_cons +let debug_loc = Wp_parameters.debug ~dkey:dkey_loc +let debug_cast = Wp_parameters.debug ~dkey:dkey_cast +let debug_access = Wp_parameters.debug ~dkey:dkey_access +let debug_valid = Wp_parameters.debug ~dkey:dkey_valid +let debug_alias = Wp_parameters.debug ~dkey:dkey_alias + +module Make(M : Sigs.Model) = +struct + let datatype = "MemDebug." ^ M.datatype + let configure = M.configure + + let hypotheses = M.hypotheses + + module Chunk = M.Chunk + + module Heap = M.Heap + module Sigma = M.Sigma + + type loc = M.loc + type chunk = M.chunk + type sigma = M.sigma + type segment = M.segment + type state = M.state + + (* ---------------------------------------------------------------------- *) + (* ---- Pretty-printing ---- *) + (* ---------------------------------------------------------------------- *) + + let pretty = M.pretty + + let state = M.state + let iter = M.iter + let lookup = M.lookup + let updates = M.updates + let apply = M.apply + + let vars = M.vars + let occurs = M.occurs + + (* ---------------------------------------------------------------------- *) + (* ---- Constructors ----- *) + (* ---------------------------------------------------------------------- *) + + let null = + let l = M.null in debug_cons "null:@, %a" pretty l; + M.null + + let literal ~eid cstr = + let l = M.literal ~eid cstr in + debug_cons "literal ~eid:%d ->@, %a" eid pretty l; + l + + let cvar x = + let l = M.cvar x in + debug_cons "cvar %a ->@, %a" Varinfo.pretty x pretty l; + l + + let pointer_loc e = + let l = M.pointer_loc e in + debug_cons "term2loc %a ->@, %a" pp_term e pretty l; + l + let pointer_val l = + let e = M.pointer_val l in + debug_cons "loc2term %a ->@, %a" pretty l pp_term e; + e + + (* ---------------------------------------------------------------------- *) + (* ---- Operations ---- *) + (* ---------------------------------------------------------------------- *) + + let field l fd = + let l' = M.field l fd in + debug_loc "@[%a.%a ->@, %a@]" pretty l Fieldinfo.pretty fd pretty l'; + l' + let shift l obj e = + let l' = M.shift l obj e in + debug_loc "@[%a+%a ->@, %a@]" pretty l pp_term e pretty l'; + l' + + let base_addr l = + let l' = M.base_addr l in + debug_loc "@[base_addr: %a -> %a@]" pretty l pretty l'; + l' + + let block_length = M.block_length + + (* ---------------------------------------------------------------------- *) + (* ---- Casting ----- *) + (* ---------------------------------------------------------------------- *) + + let cast ty l = + let l' = M.cast ty l in + debug_cast "(%a)%a -> %a" Ctypes.pretty ty.post pretty l pretty l'; + l' + + let loc_of_int obj e = + let l = M.loc_of_int obj e in + debug_cast "(%a)%a -> %a" Ctypes.pretty obj pp_term e pretty l; + l + let int_of_loc cint l = + let e = M.int_of_loc cint l in + debug_cast "(%a)%a -> %a" Ctypes.pp_int cint pretty l pp_term e; + e + + (* ---------------------------------------------------------------------- *) + (* ---- Domain ----- *) + (* ---------------------------------------------------------------------- *) + + let domain = M.domain + + (* ---------------------------------------------------------------------- *) + (* ---- Memory Access ----- *) + (* ---------------------------------------------------------------------- *) + + let load s obj l = + let v = M.load s obj l in + debug_access "@[load %a @, %a @, %a ->@, %a@]@." + Sigma.pretty s Ctypes.pretty obj pretty l (pp_value pretty) v; + v + + let stored seq obj l t = + let preds = M.stored seq obj l t in + debug_access "@[stored %a@, %a@, %a@, %a ->@, %a@]@." + (pp_sequence Sigma.pretty) seq Ctypes.pretty obj pretty l pp_term t + (Pretty_utils.pp_list pp_equation) preds; + preds + + let copied seq obj ll rl = + let preds = M.copied seq obj ll rl in + debug_access "@[copied %a@, %a@, %a@, %a ->@, %a@]@." + (pp_sequence Sigma.pretty) seq Ctypes.pretty obj pretty ll pretty rl + (Pretty_utils.pp_list pp_equation) preds; + preds + + let assigned seq obj sloc = + let preds = M.assigned seq obj sloc in + debug_access "@[assigned %a@, %a@, %a ->@, %a@]@." + (pp_sequence Sigma.pretty) seq Ctypes.pretty obj (pp_sloc pretty) sloc + (Pretty_utils.pp_list pp_equation) preds; + preds + + (* ---------------------------------------------------------------------- *) + (* ---- Pointer Comparison ----- *) + (* ---------------------------------------------------------------------- *) + + let is_null = M.is_null + let loc_eq = M.loc_eq + let loc_lt = M.loc_lt + let loc_leq = M.loc_leq + let loc_neq = M.loc_neq + let loc_diff = M.loc_diff + + (* ---------------------------------------------------------------------- *) + (* ---- Validity ----- *) + (* ---------------------------------------------------------------------- *) + + let valid s acs seg = + let p = M.valid s acs seg in + debug_valid "@[valid %a@, %a@, %a ->@, %a@]@." + Sigma.pretty s pp_acs acs (pp_rloc pretty) seg pp_pred p; + p + + let invalid s seg = + let p = M.invalid s seg in + debug_valid "@[invalid %a@, %a ->@, %a@]@." + Sigma.pretty s (pp_rloc pretty) seg pp_pred p; + p + + let scope = M.scope + let global = M.global + + (* ---------------------------------------------------------------------- *) + (* ---- Separation ----- *) + (* ---------------------------------------------------------------------- *) + + let included seg1 seg2 = + let p = M.included seg1 seg2 in + debug_alias "@[included %a@, %a ->@, %a@]@." + (pp_rloc pretty) seg1 (pp_rloc pretty) seg2 pp_pred p; + p + + let separated seg1 seg2 = + let p = M.separated seg1 seg2 in + debug_alias "@[separated %a@, %a ->@, %a@]@." + (pp_rloc pretty) seg1 (pp_rloc pretty) seg2 pp_pred p; + p + + + (** todo *) + let initialized = M.initialized + let alloc = M.alloc + let frame = M.frame + let is_well_formed = M.is_well_formed + let base_offset = M.base_offset + type domain = M.domain + let configure_ia = M.configure_ia + +end diff --git a/src/plugins/wp/MemDebug.mli b/src/plugins/wp/MemDebug.mli new file mode 100644 index 0000000000000000000000000000000000000000..79ea3456c6da70b4a662da0a1321732f4806741c --- /dev/null +++ b/src/plugins/wp/MemDebug.mli @@ -0,0 +1,38 @@ +(**************************************************************************) +(* *) +(* This file is part of WP plug-in of Frama-C. *) +(* *) +(* Copyright (C) 2007-2017 *) +(* CEA (Commissariat a l'energie atomique et aux energies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(* *) +(**************************************************************************) + +(* -------------------------------------------------------------------------- *) +(* --- Debug Memory Model --- *) +(* -------------------------------------------------------------------------- *) + +val pp_sequence : 'a Pretty_utils.formatter -> Format.formatter -> + 'a Sigs.sequence -> unit +val pp_equation : Format.formatter -> Sigs.equation -> unit +val pp_acs : Format.formatter -> Sigs.acs -> unit +val pp_value : 'a Pretty_utils.formatter -> Format.formatter -> + 'a Sigs.value -> unit +val pp_rloc : 'a Pretty_utils.formatter -> Format.formatter -> + 'a Sigs.rloc -> unit +val pp_sloc : 'a Pretty_utils.formatter -> Format.formatter -> + 'a Sigs.sloc -> unit + +module Make(M : Sigs.Model) : Sigs.Model diff --git a/src/plugins/wp/MemVal.ml b/src/plugins/wp/MemVal.ml new file mode 100644 index 0000000000000000000000000000000000000000..e95bdb4d860f14a6bbb719519ff405090452af6c --- /dev/null +++ b/src/plugins/wp/MemVal.ml @@ -0,0 +1,862 @@ +(**************************************************************************) +(* *) +(* This file is part of WP plug-in of Frama-C. *) +(* *) +(* Copyright (C) 2007-2017 *) +(* CEA (Commissariat a l'energie atomique et aux energies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(* *) +(**************************************************************************) + +(* -------------------------------------------------------------------------- *) +(* --- Value Separation Analysis' Based Memory Model --- *) +(* -------------------------------------------------------------------------- *) + +open Cil_types +open Cil_datatype +open Ctypes +open Lang +open Lang.F +open Sigs +open Definitions + +module Logic = Qed.Logic + +module type State = +sig + type t + + val bottom : t + val join : t -> t -> t + + val of_kinstr : Cil_types.kinstr -> t + val of_stmt : Cil_types.stmt -> t + val of_kf : Cil_types.kernel_function -> t + + val pretty : Format.formatter -> t -> unit +end + +module type Value = +sig + val configure : unit -> WpContext.rollback + val datatype : string + + module State : State + + type t + type state = State.t + + val null : t + val literal: eid:int -> Cstring.cst -> int * t + val cvar : varinfo -> t + + val field : t -> Cil_types.fieldinfo -> t + val shift : t -> Ctypes.c_object -> term -> t + val base_addr : t -> t + + val load : state -> t -> Ctypes.c_object -> t + + val domain : t -> Base.t list + val offset : t -> (term -> pred) + + val pretty : Format.formatter -> t -> unit +end + +module type Base = +sig +end + +let dkey = Wp_parameters.register_category "memval" (* Debugging key *) +let dkey_val = Wp_parameters.register_category "memval:val" + +let debug fmt = Wp_parameters.debug ~dkey fmt +let debug_val = Wp_parameters.debug ~dkey:dkey_val + + +(* -------------------------------------------------------------------------- *) +(* --- Logic Memory Wrapper --- *) +(* -------------------------------------------------------------------------- *) +let library = "memory" + +let a_addr = Lang.datatype ~library "addr" +let t_addr = Logic.Data(a_addr,[]) +let f_base = Lang.extern_f ~library ~result:Logic.Int + ~link:{altergo = Qed.Engine.F_subst("%1.base"); + why3 = Qed.Engine.F_subst("%1.base"); + coq = Qed.Engine.F_subst("(base %1)"); + } "base" +let f_offset = Lang.extern_f ~library ~result:Logic.Int + ~link:{altergo = Qed.Engine.F_subst("%1.offset"); + why3 = Qed.Engine.F_subst("%1.offset"); + coq = Qed.Engine.F_subst("(offset %1)"); + } "offset" +let f_shift = Lang.extern_f ~library ~result:t_addr "shift" +let f_global = Lang.extern_f ~library ~result:t_addr "global" +let f_null = Lang.extern_f ~library ~result:t_addr "null" + +let a_null = F.constant (e_fun f_null []) (* { base = 0; offset = 0 } *) +let a_base p = e_fun f_base [p] (* p -> p.offset *) +let a_offset p = e_fun f_offset [p] (* p -> p.base *) +let a_global b = e_fun f_global [b] (* b -> { base = b; offset = 0 } *) +let a_shift l k = e_fun f_shift [l;k] (* p k -> { p w/ offset = p.offset + k } *) +let a_addr b k = a_shift (a_global b) k (* b k -> { base = b; offset = k } *) + +(* -------------------------------------------------------------------------- *) +(* --- Cmath Wrapper --- *) +(* -------------------------------------------------------------------------- *) +let a_iabs i = e_fun Cmath.f_iabs [i] (* x -> |x| *) + +(* -------------------------------------------------------------------------- *) +(* --- MemValue Types --- *) +(* -------------------------------------------------------------------------- *) +(* Model utilities *) +let t_words = Logic.Array (Logic.Int, Logic.Int) (* TODO: A way to abstract this ? *) + +(* -------------------------------------------------------------------------- *) +(* --- Qed Simplifiers --- *) +(* -------------------------------------------------------------------------- *) +let phi_base t = match F.repr t with + | Logic.Fun (f, [p; _]) when f == f_shift -> a_base p + | Logic.Fun (f, [b]) when f == f_global -> b + | _ -> raise Not_found + +let phi_offset t = match F.repr t with + | Logic.Fun (f, [p; k]) when f == f_shift -> e_add (a_offset p) k + | Logic.Fun (f, _) when f == f_global -> F.e_zero + | _ -> raise Not_found + +let phi_shift p i = + if F.is_zero i then p + else match F.repr p with + | Logic.Fun (f, [q; j]) when f == f_shift -> F.e_fun f [q; F.e_add i j] + (* | Logic.Fun (f, [b]) when f == f_global -> a_addr b i *) + | _ -> raise Not_found + +let phi_read ~obj ~read ~write mem off = match F.repr mem with + | Logic.Fun (f, [_; o; v]) when f == write && off == o -> v + (*read_tau (write_tau m o v) o == v*) + | Logic.Fun (f, [m; o; _]) when f == write -> + let offset = a_iabs (F.e_sub off o) in + if F.eval_leq (F.e_int (Ctypes.sizeof_object obj)) offset then + F.e_fun read [m; off] + else raise Not_found + (*read_tau (write_tau m o v) o' == read m o' when |o - o'| <= sizeof(tau)*) + | _ -> raise Not_found + +let () = Context.register + begin fun () -> + F.set_builtin_1 f_base phi_base; + F.set_builtin_1 f_offset phi_offset; + F.set_builtin_2 f_shift phi_shift; + end + +(* -------------------------------------------------------------------------- *) +(* --- Utilities --- *) +(* -------------------------------------------------------------------------- *) +(* Wp utilities *) +module Cstring = +struct + include Cstring + + let str_cil ~eid cstr = + let enode = match cstr with + | C_str str -> Const (CStr str) + | W_str wstr -> Const (CWStr wstr) + in { + eid = eid; + enode = enode; + eloc = Location.unknown; + } +end + +(* Value utilities *) +module Base = +struct + include Base + + let bitsize_from_validity = function + | Invalid -> Integer.zero + | Empty -> Integer.zero + | Known (_, m) + | Unknown (_, _, m) -> Integer.succ m + | Variable { max_allocable } -> Integer.succ max_allocable + + let size_from_validity b = + Integer.(e_div (bitsize_from_validity b) eight) +end + + +(* -------------------------------------------------------------------------- *) +(* --- Memory Model --- *) +(* -------------------------------------------------------------------------- *) +module Make(V : Value) = +struct + (* -------------------------------------------------------------------------- *) + (* --- Model Parameters --- *) + (* -------------------------------------------------------------------------- *) + let datatype = "MemVal." ^ V.datatype + let configure () = + let rollback = V.configure () in + let orig_pointer = Context.push Lang.pointer (fun _typ -> t_addr) in + let rollback () = + rollback (); + Context.pop Lang.pointer orig_pointer; + in + rollback + + module StateRef = + struct + let model : V.State.t Context.value = Context.create "Memval.model" + let get () = Context.get model + let update () = + try + (match WpContext.get_scope () with + | WpContext.Global -> assert false + | WpContext.Kf kf -> Context.set model (V.State.of_kf kf)) + with | Invalid_argument _ -> Context.set model (V.State.of_kinstr Kglobal) + | Kernel_function.No_Definition -> assert false + end + (* -------------------------------------------------------------------------- *) + (* --- Chunk --- *) + (* -------------------------------------------------------------------------- *) + type chunk = + | M_base of Base.t + + module Chunk = + struct + type t = chunk + let self = "MemVal.Chunk" + let hash = function + | M_base b -> 5 * Base.hash b + let equal c1 c2 = match c1, c2 with + | M_base b1, M_base b2 -> Base.equal b1 b2 + let compare c1 c2 = match c1, c2 with + | M_base b1, M_base b2 -> Base.compare b1 b2 + let pretty fmt = function + | M_base b -> Base.pretty fmt b + let tau_of_chunk = function + | M_base _ -> t_words + let basename_of_base = function + | Base.Var (vi, _) -> Format.sprintf "MVar_%s" (LogicUsage.basename vi) + | Base.CLogic_Var (_, _, _) -> assert false (* not supposed to append. *) + | Base.Null -> "MNull" + | Base.String (eid, _) -> Format.sprintf "MStr_%d" eid + | Base.Allocated (vi, _dealloc, _) -> + Format.sprintf "MAlloc_%s" (LogicUsage.basename vi) + let basename_of_chunk = function + | M_base b -> basename_of_base b + let is_framed = function + | M_base b -> + try + (match WpContext.get_scope () with + | WpContext.Global -> assert false + | WpContext.Kf kf -> Base.is_formal_or_local b (Kernel_function.get_definition kf)) + with Invalid_argument _ | Kernel_function.No_Definition -> + assert false (* by context. *) + end + + let cluster () = Definitions.cluster ~id:"Default" () + + module Heap = Qed.Collection.Make(Chunk) + module Sigma = Sigma.Make(Chunk)(Heap) + + type loc = { + loc_v : V.t; + loc_t : term (* of type addr *) + } + + type sigma = Sigma.t + type segment = loc rloc + + type state = unit + let state _ = () + let iter _ _ = () + let lookup _ _ = Mterm + let updates _ _ = Bag.empty + let apply _ _ = () + + let pretty fmt l = + Format.fprintf fmt "([@ t:%a,@ v:%a @])" + F.pp_term l.loc_t + V.pretty l.loc_v + + let vars _l = Vars.empty + let occurs _x _l = false + + (* -------------------------------------------------------------------------- *) + (* --- Constructors --- *) + (* -------------------------------------------------------------------------- *) + let null = { + loc_v = V.null; + loc_t = a_null; + } + + let literal ~eid cstr = + let bid, v = V.literal ~eid cstr in + { + loc_v = v; + loc_t = a_global (F.e_int bid) + } + + let cvar x = { + loc_v = V.cvar x; + loc_t = a_addr (F.e_int (Base.id (Base.of_varinfo x))) (F.e_zero); + } + + + (* -------------------------------------------------------------------------- *) + (* --- Generated Axiomatization --- *) + (* -------------------------------------------------------------------------- *) + + module Obj = + struct + include C_object + + let compare a b = + if a==b then 0 else + match a, b with + | C_pointer _, C_pointer _ -> 0 + | _ -> compare a b + end + + module Access = WpContext.StaticGenerator(Obj) + (struct + let name = "MemVal.Access" + type key = c_object + type data = lfun * lfun + + let read suffix t_mem t_data = + let result = t_data in + let lfun = Lang.generated_f ~result "read_%s" suffix in + let xw = Lang.freshvar ~basename:"w" t_mem in + let xo = Lang.freshvar ~basename:"o" Logic.Int in + let dfun = Definitions.Logic result in + let cluster = cluster () in + Definitions.define_symbol { + d_lfun = lfun; d_types = 0; + d_params = [xw; xo]; + d_definition = dfun; + d_cluster = cluster; + }; + lfun + + let write suffix t_mem t_data = + let result = t_mem in + let lfun = Lang.generated_f ~result "write_%s" suffix in + let xw = Lang.freshvar ~basename:"w" t_mem in + let xo = Lang.freshvar ~basename:"o" Logic.Int in + let xv = Lang.freshvar ~basename:"v" t_data in + let dfun = Definitions.Logic result in + let cluster = cluster () in + Definitions.define_symbol { + d_lfun = lfun; d_types = 0; + d_params = [xw; xo; xv]; + d_definition = dfun; + d_cluster = cluster; + }; + lfun + + let axiomatize ~obj suffix t_mem t_data f_rd f_wr = + let name = "axiom_" ^ suffix in + let xw = Lang.freshvar ~basename:"w" t_mem in + let w = e_var xw in + let xo = Lang.freshvar ~basename:"o" Logic.Int in + let o = e_var xo in + let xv = Lang.freshvar ~basename:"v" t_data in + let v = e_var xv in + let p_write = p_call f_wr [w; o; v] in + let p_read = p_call f_rd [e_prop p_write; o] in + let lemma = p_equal (e_prop p_read) v in + let cluster = cluster () in + if not (Wp_parameters.debug_atleast 1) then begin + F.set_builtin_2 f_rd (phi_read ~obj ~read:f_rd ~write:f_wr) + end; + Definitions.define_lemma { + l_kind = `Axiom; + l_name = name; l_types = 0; + l_triggers = []; + l_forall = [xw; xo; xv]; + l_lemma = lemma; + l_cluster = cluster; + } + + let axiomatize2 ~obj suffix t_mem t_data f_rd f_wr = + let name = "axiom_" ^ suffix ^ "_2" in + let xw = Lang.freshvar ~basename:"w" t_mem in + let w = e_var xw in + let xwo = Lang.freshvar ~basename:"xwo" Logic.Int in + let wo = e_var xwo in + let xro = Lang.freshvar ~basename:"xro" Logic.Int in + let ro = e_var xro in + let xv = Lang.freshvar ~basename:"v" t_data in + let v = e_var xv in + let p_write = p_call f_wr [w; wo; v] in + let p_read = p_call f_rd [e_prop p_write; ro] in + let sizeof = (F.e_int (Ctypes.sizeof_object obj)) in + let offset = a_iabs (F.e_sub ro wo) in + let lemma = + F.p_imply + (F.p_leq sizeof offset) + (F.p_equal (e_prop p_read) (e_prop (p_call f_rd [w; ro]))) + in + let cluster = cluster () in + Definitions.define_lemma { + l_kind = `Axiom; + l_name = name; l_types = 0; + l_triggers = []; + l_forall = [xw; xwo; xro; xv]; + l_lemma = lemma; + l_cluster = cluster; + } + + let generate obj = + let suffix = Ctypes.basename obj in + let t_mem = t_words in + let t_data = Lang.tau_of_object obj in + let d_read = read suffix t_mem t_data in + let d_write = write suffix t_mem t_data in + axiomatize ~obj suffix t_mem t_data d_read d_write; + axiomatize2 ~obj suffix t_mem t_data d_read d_write; + d_read, d_write + + let compile = Lang.local generate + end) + + let read obj ~mem ~offset = + F.e_fun (fst (Access.get obj)) [mem; offset] + let write obj ~mem ~offset ~value = + F.e_fun (snd (Access.get obj)) [mem; offset; value] + + let fold_ite f l = + let rec aux = function + | [] -> assert false + | [x] -> f x + | x :: xs -> + F.e_if + (F.e_eq (a_base l.loc_t) (F.e_int (Base.id x))) + (f x) + (aux xs) + in + aux (V.domain l.loc_v) + + let fold_ite_pred f l = + let rec aux = function + | [] -> assert false + | [x] -> f x + | x :: xs -> + F.p_if + (F.p_equal (a_base l.loc_t) (F.e_int (Base.id x))) + (f x) + (aux xs) + in + aux (V.domain l.loc_v) + + (* -------------------------------------------------------------------------- *) + (* --- Logic to Location (and resp.) --- *) + (* -------------------------------------------------------------------------- *) + let pointer_loc _ = Warning.error ~source:"MemVal" "Cannot build top from EVA" + + let pointer_val l = l.loc_t + + + (* -------------------------------------------------------------------------- *) + (* --- Lifting --- *) + (* -------------------------------------------------------------------------- *) + let field l fd = + let offs = Integer.of_int (Ctypes.field_offset fd) in + { + loc_v = V.field l.loc_v fd; + loc_t = a_shift l.loc_t (F.e_bigint offs); + } + + let shift l obj k = + let size = Integer.of_int (Ctypes.sizeof_object obj) in + let offs = F.e_times size k in + { + loc_v = V.shift l.loc_v obj k; + loc_t = a_shift l.loc_t offs; + } + + let base_addr l = + { + loc_v = V.base_addr l.loc_v; + loc_t = a_addr (a_base l.loc_t) F.e_zero; + } + + let block_length _s _obj l = + let size_from_base base = + F.e_bigint Base.(size_from_validity (validity base)) + in + fold_ite size_from_base l + + (* -------------------------------------------------------------------------- *) + (* --- Casting --- *) + (* -------------------------------------------------------------------------- *) + let cast _ l = l + + let loc_of_int _ v = + if F.is_zero v then null + else + (*TODO: Reinterpret integer with Value *) + Warning.error ~source:"MemVal Model" + "Forbidden cast of int to pointer" + + let int_of_loc _ l = pointer_val l + + let domain _ l = + let d = V.domain l.loc_v in + assert (d <> []); + List.fold_left + (fun acc b -> Heap.Set.add (M_base b) acc) + Heap.Set.empty d + + (* -------------------------------------------------------------------------- *) + (* --- Memory Load --- *) + (* -------------------------------------------------------------------------- *) + let load_value sigma obj l = + let load_base base = + let mem = Sigma.value sigma (M_base base) in + let offset = a_offset l.loc_t in + read obj ~mem ~offset + in + let t = fold_ite load_base l in + begin if Wp_parameters.has_dkey dkey_val then + let v = V.load (StateRef.get ()) l.loc_v obj in + debug_val "load: %a -> %a" V.pretty l.loc_v V.pretty v + end; + Val t + + let load_loc ~assume sigma obj l = + let load_base v' base = + let mem = Sigma.value sigma (M_base base) in + let offset = a_offset l.loc_t in + let rd = read obj ~mem ~offset in + if assume then begin + let pred = V.offset v' (a_offset rd) in + Lang.assume pred (* Yet another mutable. *) + end; + rd + in + let v' = V.load (StateRef.get ()) l.loc_v obj in + let t = fold_ite (load_base v') l in + Loc { + loc_v = V.load (StateRef.get ()) l.loc_v obj; + loc_t = t; + } + + let load : sigma -> c_object -> loc -> loc value = fun sigma obj l -> + StateRef.update (); + begin match obj with + | C_int _ | C_float _ -> load_value sigma obj l + | C_pointer _ -> load_loc ~assume:true sigma obj l + | _ -> load_loc ~assume:false sigma obj l + end + + (* -------------------------------------------------------------------------- *) + (* --- Memory Store --- *) + (* -------------------------------------------------------------------------- *) + let stored : sigma sequence -> c_object -> loc -> term -> equation list = fun seq obj l v -> + let mk_write cond base = + let wpre = Sigma.value seq.pre (M_base base) in + let wpost = Sigma.value seq.post (M_base base) in + let write = write obj ~mem:wpre ~offset:(a_offset l.loc_t) ~value:v in + F.p_equal wpost (F.e_if cond write wpre) + in + let rec store acc = function + | [] -> assert false + | [c] -> + let cond = F.e_and ((List.map (F.e_neq (a_base l.loc_t))) acc) in + [ Assert (mk_write cond c) ] + | c :: cs -> + let bid = (F.e_int (Base.id c)) in + let cond = F.e_eq (a_base l.loc_t) bid in + [ Assert (mk_write cond c) ] + @ store (bid :: acc) cs + in + store [ ] (V.domain l.loc_v) + + let copied seq obj ll lr = + let v = match load seq.pre obj lr with + | Sigs.Val v -> v + | Sigs.Loc l -> l.loc_t + in + stored seq obj ll v + + let assigned _s _obj _sloc = [ Assert F.p_true ] + + + (* -------------------------------------------------------------------------- *) + (* --- Pointer Comparison --- *) + (* -------------------------------------------------------------------------- *) + let is_null l = p_equal l.loc_t a_null + + let loc_delta l1 l2 = + match F.is_equal (a_base l1.loc_t) (a_base l2.loc_t) with + | Logic.Yes -> F.e_sub (a_offset l1.loc_t) (a_offset l2.loc_t) + | Logic.Maybe | Logic.No -> + Warning.error "Can only compare pointers with same base." + + let base_eq l1 l2 = F.p_equal (a_base l1.loc_t) (a_base l2.loc_t) + let offset_cmp cmpop l1 l2 = cmpop (a_offset l1.loc_t) (a_offset l2.loc_t) + + let loc_diff _obj l1 l2 = loc_delta l1 l2 + let loc_eq l1 l2 = F.p_and (base_eq l1 l2) (offset_cmp F.p_equal l1 l2) + let loc_lt l1 l2 = F.p_lt (loc_delta l1 l2) F.e_zero + let loc_leq l1 l2 = F.p_leq (loc_delta l1 l2) F.e_zero + let loc_neq l1 l2 = F.p_neq (loc_delta l1 l2) F.e_zero + + (* -------------------------------------------------------------------------- *) + (* --- Segments --- *) + (* -------------------------------------------------------------------------- *) + + type range = + | LOC of loc * term (*size*) + | RANGE of loc * Vset.set (* offset range access from *loc* *) + + let range_of_rloc = function + | Rloc (obj, l) -> + LOC (l, F.e_int (Ctypes.sizeof_object obj)) + | Rrange (l, obj, Some a, Some b) -> + let la = shift l obj a in + let n = e_fact (Ctypes.sizeof_object obj) (F.e_range a b) in + LOC (la, n) + | Rrange (l, obj, a_opt, b_opt) -> + let f = F.e_fact (Ctypes.sizeof_object obj) in + RANGE (l, Vset.range (Extlib.opt_map f a_opt) (Extlib.opt_map f b_opt)) + + (* -------------------------------------------------------------------------- *) + (* --- Validity --- *) + (* -------------------------------------------------------------------------- *) + (** [vset_from_validity base] returns the logical set of all valid bytes of + [base]. **) + let vset_from_validity = function + | Base.Empty -> Vset.empty + | Base.Invalid -> Vset.singleton F.e_zero + | Base.Known (min_valid, max_valid) + | Base.Unknown (min_valid, Some max_valid, _) -> + (* valid between min_valid .. max_valid inclusive *) + let mn = F.e_bigint Integer.(e_div min_valid eight) in + let mx = F.e_bigint Integer.(e_div max_valid eight) in + Vset.range (Some mn) (Some mx) + | Base.Variable { Base.min_alloc = min_valid } -> + (* valid between 0 .. min_valid inclusive *) + let mn_valid = F.e_bigint Integer.(e_div min_valid eight) in + Vset.range (Some F.e_zero) (Some mn_valid) + | Base.Unknown (_, None, _) -> Vset.empty + + let valid_range : sigma -> acs -> range -> pred = fun _ acs r -> + let for_writing = match acs with RW -> true | RD -> false + | OBJ -> true (* TODO: *) in + let l, base_offset = match r with + | LOC (l, n) -> + let a = a_offset l.loc_t in + let b = F.e_add a (F.e_sub n F.e_one) in + l, Vset.range (Some a) (Some b) + | RANGE (l, r) -> l, Vset.lift_add (Vset.singleton l.loc_t) r + in + let valid_base set base = + if for_writing && (Base.is_read_only base) then + F.p_false + else + let base_vset = vset_from_validity (Base.validity base) in + Vset.subset set base_vset + in + fold_ite_pred (valid_base base_offset) l + + (** [valid sigma acs seg] returns the formula that tests if a given memory + segment [seg] (in bytes) is valid (according to [acs]) at memory state + [sigma]. **) + let valid : sigma -> acs -> segment -> pred = fun s acs seg -> + valid_range s acs (range_of_rloc seg) + + let invalid = fun _ _ -> F.p_true (* TODO *) + + (* -------------------------------------------------------------------------- *) + (* --- Scope --- *) + (* -------------------------------------------------------------------------- *) + let alloc_sigma : sigma -> varinfo list -> sigma = fun sigma xs -> + let alloc sigma x = + let havoc s c = Sigma.havoc_chunk s (M_base c) in + let v = V.cvar x in + List.fold_left havoc sigma (V.domain v) + in + List.fold_left alloc sigma xs + + let alloc_pred _ _ _ = [] + + let alloc sigma xs = + if xs = [] then sigma else alloc_sigma sigma xs + + let scope : sigma sequence -> scope -> varinfo list -> pred list = fun seq scope xs -> + match scope with + | Enter -> [] + | Leave -> + alloc_pred seq xs () + + let scope seq sc xs = + let preds = scope seq sc xs in + debug "[scope pre:%a post:%a xs:%a] -> preds:%a" + Sigma.pretty seq.pre + Sigma.pretty seq.post + (Pretty_utils.pp_iter ~sep:" " List.iter Varinfo.pretty) xs + (Pretty_utils.pp_iter ~sep:" " List.iter pp_pred) preds; + preds + + let global : sigma -> term (*addr*) -> pred = fun _ _ -> + F.p_true (* True is harmless and WP never call this function... *) + + + (* -------------------------------------------------------------------------- *) + (* --- Separation --- *) + (* -------------------------------------------------------------------------- *) + let range_to_base_offset = function + | LOC (l, n) -> + let a = a_offset l.loc_t in + let b = F.e_add a n in + l, Vset.range (Some a) (Some b) + | RANGE (l, r) -> l, Vset.lift_add (Vset.singleton l.loc_t) r + + let included : segment -> segment -> pred = fun s1 s2 -> + (* (b1 = b2) -> (r1 \in r2) *) + let l1, vs1 = range_to_base_offset (range_of_rloc s1) in + let l2, vs2 = range_to_base_offset (range_of_rloc s2) in + p_and + (p_equal (a_base l1.loc_t) (a_base l2.loc_t)) + (Vset.subset vs1 vs2) + + let separated : segment -> segment -> pred = fun s1 s2 -> + (* (b1 = b2) -> (r1 \cap r2) = \empty *) + let l1, vs1 = range_to_base_offset (range_of_rloc s1) in + let l2, vs2 = range_to_base_offset (range_of_rloc s2) in + p_and + (p_equal (a_base l1.loc_t) (a_base l2.loc_t)) + (Vset.disjoint vs1 vs2) + + let initialized _sigma _l = F.p_true (* todo *) + let is_well_formed _ = F.p_true (* todo *) + let base_offset _loc = assert false (** TODO *) + type domain = Sigma.domain + let no_binder = { bind = fun _ f v -> f v } + let configure_ia _ = no_binder (* todo *) + let hypotheses x = x (* todo *) + let frame _sigma = [] (* todo *) + +end + + + + +(* -------------------------------------------------------------------------- *) +(* --- EVA Instance --- *) +(* -------------------------------------------------------------------------- *) +module Eva = +struct + open Cvalue + + let datatype = "Eva" + let configure () = + if not (Db.Value.is_computed ()) then + Wp_parameters.abort ~current:true + "Could not use Eva memory model without a previous run of the analysis."; + (fun () -> ()) + + module State = + struct + type t = Model.t + + let bottom = Model.bottom + let join = Model.join + + let of_kinstr k = Db.Value.get_state k + let of_stmt k = Db.Value.get_stmt_state k + let of_kf kf = + let state = ref bottom in + let vis = object + inherit Cil.nopCilVisitor + method !vstmt stmt = + state := join (of_stmt stmt) !state; + Cil.DoChildren + end in + ignore (Cil.visitCilFunction vis (Kernel_function.get_definition kf)); + !state + + let pretty = Model.pretty + end + + type t = V.t + type state = Model.t + + let null = V.inject Base.null Ival.zero + let literal ~eid cstr = + let b = Base.of_string_exp (Cstring.str_cil ~eid cstr) in + Base.id b, V.inject b Ival.zero + let cvar x = V.inject (Base.of_varinfo x) Ival.zero + + let field v fd = + let bsize = Ctypes.field_offset fd |> Integer.of_int in + let offs = Ival.inject_singleton bsize in + Cvalue.V.shift offs v + let shift v obj t = + let bsize = 8 * Ctypes.sizeof_object obj |> Integer.of_int in + let offs = match F.repr t with + | Logic.Kint z -> Ival.inject_singleton (Integer.mul bsize z) + | _ -> Ival.top in + Cvalue.V.shift offs v + let base_addr v = + Cvalue.V.fold_topset_ok + (fun b _ v -> Cvalue.V.add b Ival.zero v) + v (Cvalue.V.bottom) + + let load state v obj = + let bsize = 8 * Ctypes.sizeof_object obj in + let bits = Locations.loc_bytes_to_loc_bits v in + let int_base = bsize |> Integer.of_int |> Int_Base.inject in + let vloc = Locations.make_loc bits int_base in + Cvalue.Model.find state vloc + + let domain v = + Cvalue.V.fold_topset_ok + (fun b _ acc -> b :: acc) + v [] + + let logic_ival ival = fun x -> + (* assert (not (Ival.is_float ival)); (\* by integer offsets *\) *) + match Ival.project_small_set ival with + | Some is -> + F.p_any + (fun i -> F.p_equal x (F.e_bigint i)) + is + | None -> begin + match Ival.min_and_max ival with + | Some mn, Some mx -> + F.p_and + (F.p_leq (F.e_bigint mn) x) + (F.p_leq x (F.e_bigint mx)) + | Some mn, None -> F.p_leq (F.e_bigint mn) x + | None, Some mx -> F.p_leq x (F.e_bigint mx) + | None, None -> F.p_true + end + + let offset v = fun x -> + let ivals = + Cvalue.V.fold_topset_ok + (fun _ ival acc -> ival :: acc) + v [] + in + F.p_any (fun ival -> logic_ival ival x) ivals + + let pretty = Cvalue.V.pretty + +end diff --git a/src/plugins/wp/MemVal.mli b/src/plugins/wp/MemVal.mli new file mode 100644 index 0000000000000000000000000000000000000000..995ee9def5f978fa198cf8b31d956b4e5de76993 --- /dev/null +++ b/src/plugins/wp/MemVal.mli @@ -0,0 +1,84 @@ +(**************************************************************************) +(* *) +(* This file is part of WP plug-in of Frama-C. *) +(* *) +(* Copyright (C) 2007-2017 *) +(* CEA (Commissariat a l'energie atomique et aux energies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(* *) +(**************************************************************************) +open Lang.F + +module type State = +sig + type t (** abstract state **) + + val bottom : t + val join : t -> t -> t + + val of_kinstr : Cil_types.kinstr -> t + (** [of_stmt stmt] get the abstract state of [stmt]. **) + val of_stmt : Cil_types.stmt -> t + (** [of_kf kf] get the join state of all [kf]'s statements states **) + val of_kf : Cil_types.kernel_function -> t + + val pretty : Format.formatter -> t -> unit +end + +module type Value = +sig + val configure : unit -> WpContext.rollback + val datatype : string + + module State : State + + type t (** abstract value **) + type state = State.t + + val null : t + (** [literal eid cstr] returns the pair of base identifier and abstract value + corresponding to the concrete string constant [cstr] of unique expression + identifier [eid]. [eid] should be a valid identifier for [cstr]. **) + val literal: eid:int -> Cstring.cst -> int * t + (** [cvar x] returns the abstract value corresponding to &[x]. **) + val cvar : Cil_types.varinfo -> t + + (** [field v fd] returns the value obtained by access to field [fd] + from [v]. **) + val field : t -> Cil_types.fieldinfo -> t + (** [shift v obj k] returns the value obtained by access at an index [k] + with type [obj] from [v]. **) + val shift : t -> Ctypes.c_object -> term -> t + (** [base_addr v] returns the value corresponding to the base address + of [v]. **) + val base_addr : t -> t + + (** [load s v obj] returns the value at the location given by [v] with type + [obj] within the state [s]. **) + val load : state -> t -> Ctypes.c_object -> t + + (** [domain v] returns a list of all possible concrete bases of [v]. **) + val domain : t -> Base.t list + (** [offset v] returns a function which when applied with a term returns + a predicate over [v]'s offset. *) + val offset : t -> (term -> pred) + + val pretty : Format.formatter -> t -> unit +end + +module Make(V : Value) : Sigs.Model + +(** The glue between WP and EVA. **) +module Eva : Value diff --git a/src/plugins/wp/MemValue.ml b/src/plugins/wp/MemValue.ml index e597f0d148304425b04afb34973187d0c635ff7e..fb301c91c31eb557d9032dec5468cef2ff9630d3 100644 --- a/src/plugins/wp/MemValue.ml +++ b/src/plugins/wp/MemValue.ml @@ -260,7 +260,7 @@ struct | M_float -> L.Array (t_addr, L.Real) | M_base _ -> L.Array (L.Int, t_addr) let basename_of_chunk c = match c with - | M_int -> "Mint00" + | M_int -> "Mint" | M_char -> "Mchar" | M_float -> "Mfloat" | M_base b -> match b with diff --git a/src/plugins/wp/tests/wp_eva/oracle/simple.0.res.oracle b/src/plugins/wp/tests/wp_eva/oracle/simple.0.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..92b9b4f7d77774f6f0964f10057341f22fc1cddd --- /dev/null +++ b/src/plugins/wp/tests/wp_eva/oracle/simple.0.res.oracle @@ -0,0 +1,34 @@ +[kernel] Parsing tests/wp_eva/simple.c (with preprocessing) +[eva:alarm] tests/wp_eva/simple.c:14: Warning: assertion got status unknown. +[eva:alarm] tests/wp_eva/simple.c:19: Warning: assertion got status unknown. +[wp] Running WP plugin... +[wp] tests/wp_eva/simple.c:28: Warning: + Ignored 'terminates' specification: + \false +[wp] Warning: Missing RTE guards +------------------------------------------------------------ + Function f +------------------------------------------------------------ + +Goal Assertion (file tests/wp_eva/simple.c, line 14): +Let x = read_sint32(MVar_z_0, 0). +Let x_1 = 1 + x. +Assume { Type: is_sint32(x) /\ is_sint32(x_1). } +Prove: P_P(x_1). + +------------------------------------------------------------ +------------------------------------------------------------ + Function g +------------------------------------------------------------ + +Goal Assertion (file tests/wp_eva/simple.c, line 19): +Let x = read_sint32(MVar_x_0, 0). +Let x_1 = read_sint32(MVar_y_0, 0). +Let x_2 = read_sint32(MVar_z_0, 0). +Let x_3 = 1 + x. +Assume { + Type: is_sint32(x) /\ is_sint32(x_1) /\ is_sint32(x_2) /\ is_sint32(x_3). +} +Prove: P_P(x_1) /\ P_P(x_2) /\ P_P(x_3). + +------------------------------------------------------------ diff --git a/src/plugins/wp/tests/wp_eva/oracle/simple.1.res.oracle b/src/plugins/wp/tests/wp_eva/oracle/simple.1.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..86e4a5f5820efd8db29cfe0d5c89475be734e776 --- /dev/null +++ b/src/plugins/wp/tests/wp_eva/oracle/simple.1.res.oracle @@ -0,0 +1,36 @@ +[kernel] Parsing tests/wp_eva/simple.c (with preprocessing) +[eva:alarm] tests/wp_eva/simple.c:14: Warning: assertion got status unknown. +[eva:alarm] tests/wp_eva/simple.c:19: Warning: assertion got status unknown. +[wp] Running WP plugin... +[wp] tests/wp_eva/simple.c:28: Warning: + Ignored 'terminates' specification: + \false +[wp] Warning: Missing RTE guards +------------------------------------------------------------ + Function f +------------------------------------------------------------ + +Goal Assertion (file tests/wp_eva/simple.c, line 14): +Let x = Mint_0[shift(global(Base_1_0), Offs_0)]. +Let x_1 = 1 + x. +Assume { Type: is_sint32(x) /\ is_sint32(x_1). } +Prove: P_P(x_1). + +------------------------------------------------------------ +------------------------------------------------------------ + Function g +------------------------------------------------------------ + +Goal Assertion (file tests/wp_eva/simple.c, line 19): +Let a = shift(global(Base_8_0), Offs_0). +Let x = Mint_0[a]. +Let x_1 = 1 + x. +Let m = Mint_0[a <- x_1]. +Let x_2 = m[shift(global(Base_4_0), Offs_1)]. +Let x_3 = m[shift(global(Base_6_0), Offs_2)]. +Assume { + Type: is_sint32(x) /\ is_sint32(x_1) /\ is_sint32(x_2) /\ is_sint32(x_3). +} +Prove: P_P(x_1) /\ P_P(x_2) /\ P_P(x_3). + +------------------------------------------------------------ diff --git a/src/plugins/wp/tests/wp_eva/simple.c b/src/plugins/wp/tests/wp_eva/simple.c new file mode 100644 index 0000000000000000000000000000000000000000..4e5a58321e7c70d96becf638c5f5992922a0f884 --- /dev/null +++ b/src/plugins/wp/tests/wp_eva/simple.c @@ -0,0 +1,28 @@ +#include "__fc_builtin.h" + +/*@ + axiomatic P { + predicate P(int x); + } + + @*/ + +int z; + +void f (int *x, int *y){ + *x = *x+1; + /*@ assert P(*x) && P(*y) && P(z); @*/ +} + +void g (int *x, int *y){ + *x = *x+1; + /*@ assert P(*x) && P(*y) && P(z); @*/ +} + +void main(){ + int x = Frama_C_interval(2,1000); + int y = Frama_C_interval(2,1000); + z = Frama_C_interval(2,1000); + f(&z,&z); + g(&x,&y); +} diff --git a/src/plugins/wp/tests/wp_eva/test_config b/src/plugins/wp/tests/wp_eva/test_config new file mode 100644 index 0000000000000000000000000000000000000000..c01e5325329837427b6260c71f109832da34cf7a --- /dev/null +++ b/src/plugins/wp/tests/wp_eva/test_config @@ -0,0 +1,3 @@ +CMD: @frama-c@ -no-autoload-plugins -load-module eva,scope -eva -load-module wp -eva-no-print -eva-verbose 0 +OPT: -then -wp -wp-print -wp-prover none -wp-share ./share -wp-msg-key shell -wp-model eva1 +OPT: -then -wp -wp-print -wp-prover none -wp-share ./share -wp-msg-key shell -wp-model eva2