diff --git a/headers/header_spec.txt b/headers/header_spec.txt index 536e8d2c9c8ba5d81f399c5acd2ea78861fc6c04..f0c4e42477c13c469e62ed6ef2307b7492ac817c 100644 --- a/headers/header_spec.txt +++ b/headers/header_spec.txt @@ -1408,6 +1408,8 @@ src/plugins/wp/MemoryContext.ml: CEA_WP src/plugins/wp/MemoryContext.mli: CEA_WP src/plugins/wp/MemEmpty.ml: CEA_WP src/plugins/wp/MemEmpty.mli: CEA_WP +src/plugins/wp/MemLoader.ml: CEA_WP +src/plugins/wp/MemLoader.mli: CEA_WP src/plugins/wp/MemTyped.ml: CEA_WP src/plugins/wp/MemTyped.mli: CEA_WP src/plugins/wp/MemVar.ml: CEA_WP diff --git a/src/plugins/wp/Lang.ml b/src/plugins/wp/Lang.ml index 2ba8603148d81bef9b2ec9b53360ab91c4c5bf55..97ab4e5e7ccc7b273ca0deb225bb116d48873d88 100644 --- a/src/plugins/wp/Lang.ml +++ b/src/plugins/wp/Lang.ml @@ -176,7 +176,7 @@ let t_int = Logic.Int let t_bool = Logic.Bool let t_real = Logic.Real let t_prop = Logic.Prop -let t_addr () = Context.get pointer (Cil_types.TVoid []) +let t_addr () = Context.get pointer Cil.voidType let t_array a = Logic.Array(Logic.Int,a) let t_farray a b = Logic.Array(a,b) let t_datatype adt ts = Logic.Data(adt,ts) diff --git a/src/plugins/wp/Lang.mli b/src/plugins/wp/Lang.mli index af9ac3bb08b228a2aed5effed33e13389dfdddff..7ef00de80b20a5fd7a7905706a7a05b7666afac2 100644 --- a/src/plugins/wp/Lang.mli +++ b/src/plugins/wp/Lang.mli @@ -162,7 +162,7 @@ val t_int : tau val t_real : tau val t_bool : tau val t_prop : tau -val t_addr : unit -> tau +val t_addr : unit -> tau (** pointer on Void *) val t_array : tau -> tau val t_farray : tau -> tau -> tau val t_datatype : adt -> tau list -> tau diff --git a/src/plugins/wp/Makefile.in b/src/plugins/wp/Makefile.in index 4fed7ec6a85f4c349759b0f59b7cefef24b54c4e..b43a9ba9384e19c262b705d4de3bab97ce20ba5b 100644 --- a/src/plugins/wp/Makefile.in +++ b/src/plugins/wp/Makefile.in @@ -80,7 +80,8 @@ PLUGIN_CMO:= \ CodeSemantics \ LogicCompiler \ LogicSemantics LogicAssigns \ - Sigma MemEmpty MemZeroAlias MemVar MemTyped \ + Sigma MemLoader \ + MemEmpty MemZeroAlias MemVar MemTyped \ wpStrategy wpRTE wpAnnot \ CfgCompiler StmtSemantics \ VCS script proof wpo wpReport \ diff --git a/src/plugins/wp/MemLoader.ml b/src/plugins/wp/MemLoader.ml new file mode 100644 index 0000000000000000000000000000000000000000..bfe4d75df24c91bf60afe227a14a1cdfc1dc59f3 --- /dev/null +++ b/src/plugins/wp/MemLoader.ml @@ -0,0 +1,372 @@ +(**************************************************************************) +(* *) +(* This file is part of WP plug-in of Frama-C. *) +(* *) +(* Copyright (C) 2007-2019 *) +(* 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). *) +(* *) +(**************************************************************************) + +(* -------------------------------------------------------------------------- *) +(* --- Memory Model --- *) +(* -------------------------------------------------------------------------- *) + +open Cil_types +open Cil_datatype +open Definitions +open Ctypes +open Lang +open Lang.F +open Sigs + +(* -------------------------------------------------------------------------- *) +(* --- Compound Loader --- *) +(* -------------------------------------------------------------------------- *) + +let cluster () = + Definitions.cluster ~id:"Compound" ~title:"Memory Compound Loader" () + +type frame = string * Definitions.trigger list * pred list * term * term + +module type Model = +sig + + module Chunk : Chunk + module Sigma : Sigma with type chunk = Chunk.t + + val name : string + + type loc + val sizeof : c_object -> int + val field : loc -> fieldinfo -> loc + val shift : loc -> c_object -> term -> loc + + val to_addr : loc -> term + val to_region_pointer : loc -> int * term + val of_region_pointer : int -> c_object -> term -> loc + + val domain : c_object -> loc -> Sigma.domain + val frames : c_object -> loc -> Chunk.t -> frame list + + val last : Sigma.t -> c_object -> loc -> term + + val havoc : c_object -> loc -> length:term -> + Chunk.t -> fresh:term -> current:term -> term + + val eqmem : c_object -> loc -> Chunk.t -> term -> term -> pred + + val eqmem_forall : + c_object -> loc -> Chunk.t -> term -> term -> var list * pred * pred + + val load_int : Sigma.t -> c_int -> loc -> term + val load_float : Sigma.t -> c_float -> loc -> term + val load_pointer : Sigma.t -> typ -> loc -> loc + + val store_int : Sigma.t -> c_int -> loc -> term -> Chunk.t * term + val store_float : Sigma.t -> c_float -> loc -> term -> Chunk.t * term + val store_pointer : Sigma.t -> typ -> loc -> term -> Chunk.t * term + +end + +module Make (M : Model) = +struct + + type chunk = M.Chunk.t + + module Chunk = M.Chunk + module Sigma = M.Sigma + module Domain = M.Sigma.Chunk.Set + + let signature ft = + let s = Sigma.create () in + let xs = ref [] in + let cs = ref [] in + Domain.iter + (fun c -> + cs := c :: !cs ; + xs := (Sigma.get s c) :: !xs ; + ) ft ; + List.rev !xs , List.rev !cs , s + + let pp_rid fmt r = if r <> 0 then Format.fprintf fmt "_R%03d" r + + let loadrec = ref (fun _ _ _ -> assert false) + + (* -------------------------------------------------------------------------- *) + (* --- Frame Lemmas for Compound Access --- *) + (* -------------------------------------------------------------------------- *) + + let memories sigma chunks = List.map (Sigma.value sigma) chunks + let assigned sigma c m chunks = + List.map + (fun c0 -> if Chunk.equal c0 c then m else Sigma.value sigma c0) + chunks + + let frame_lemmas phi obj loc params chunks = + begin + let prefix = Fun.debug phi in + let sigma = Sigma.create () in + List.iter + (fun chunk -> + List.iter + (fun (name,triggers,conditions,m1,m2) -> + let mem1 = assigned sigma chunk m1 chunks in + let mem2 = assigned sigma chunk m2 chunks in + let value1 = e_fun phi (params @ mem1) in + let value2 = e_fun phi (params @ mem2) in + let vars1 = F.vars value1 in + let vars2 = F.vars value2 in + let l_triggers = + if Vars.subset vars1 vars2 then + [ (Trigger.of_term value2 :: triggers ) ] + else + if Vars.subset vars2 vars1 then + [ (Trigger.of_term value1 :: triggers ) ] + else + [ (Trigger.of_term value1 :: triggers ); + (Trigger.of_term value2 :: triggers ) ] + in + let l_name = Pretty_utils.sfprintf "%s_%s_%a" + prefix name Chunk.pretty chunk in + let l_lemma = F.p_hyps conditions (p_equal value1 value2) in + Definitions.define_lemma { + l_assumed = true ; + l_name ; l_types = 0 ; + l_triggers ; + l_forall = F.p_vars l_lemma ; + l_lemma = l_lemma ; + l_cluster = cluster () ; + } + ) (M.frames obj loc chunk) + ) chunks + end + + (* -------------------------------------------------------------------------- *) + (* --- Compound Loader --- *) + (* -------------------------------------------------------------------------- *) + + module COMP_KEY = + struct + type t = int * compinfo + let compare (r,c) (r',c') = if r=r' then Compinfo.compare c c' else r-r' + let pretty fmt (r,c) = Format.fprintf fmt "%d:%a" r Compinfo.pretty c + end + + module COMP = Model.Generator(COMP_KEY) + (struct + let name = M.name ^ ".COMP" + type key = int * compinfo + type data = lfun * chunk list + + let generate (r,c) = + let x = Lang.freshvar ~basename:"p" (Lang.t_addr()) in + let v = e_var x in + let obj = C_comp c in + let loc = M.of_region_pointer r obj v in (* t_pointer -> loc *) + let domain = M.domain obj loc in + let result = Lang.tau_of_comp c in + let lfun = Lang.generated_f ~result "Load%a_%s" pp_rid r (Lang.comp_id c) in + (* Since its a generated it is the unique name given *) + let xms,chunks,sigma = signature domain in + let def = List.map + (fun f -> + Cfield f , !loadrec sigma (object_of f.ftype) (M.field loc f) + ) c.cfields in + let dfun = Definitions.Function( result , Def , e_record def ) in + Definitions.define_symbol { + d_lfun = lfun ; d_types = 0 ; + d_params = x :: xms ; + d_definition = dfun ; + d_cluster = cluster () ; + } ; + frame_lemmas lfun obj loc [v] chunks ; + lfun , chunks + + let compile = Lang.local generate + end) + + (* -------------------------------------------------------------------------- *) + (* --- Array Loader --- *) + (* -------------------------------------------------------------------------- *) + + module ARRAY_KEY = + struct + type t = int * arrayinfo * Matrix.matrix + let pretty fmt (r,_,m) = + Format.fprintf fmt "%d:%a" r Matrix.NATURAL.pretty m + let compare (r1,_,m1) (r2,_,m2) = + if r1 = r2 then Matrix.NATURAL.compare m1 m2 else r1-r2 + end + + module ARRAY = Model.Generator(ARRAY_KEY) + (struct + open Matrix + let name = M.name ^ ".ARRAY" + type key = int * arrayinfo * Matrix.matrix + type data = lfun * chunk list + + let generate (r,ainfo,(obj_e,ds)) = + let x = Lang.freshvar ~basename:"p" (Lang.t_addr()) in + let v = e_var x in + let obj_a = C_array ainfo in + let loc = M.of_region_pointer r obj_a v in (* t_pointer -> loc *) + let domain = M.domain obj_a loc in + let result = Matrix.tau obj_e ds in + let lfun = Lang.generated_f ~result "Array%a%s_%s" pp_rid r + (Matrix.id ds) (Matrix.natural_id obj_e) in + let prefix = Lang.Fun.debug lfun in + let axiom = prefix ^ "_access" in + let xmem,chunks,sigma = signature domain in + let denv = Matrix.denv ds in + let phi = e_fun lfun (v :: denv.size_val @ List.map e_var xmem) in + let va = List.fold_left e_get phi denv.index_val in + let ofs = e_sum denv.index_offset in + let vm = !loadrec sigma obj_e (M.shift loc obj_e ofs) in + let lemma = p_hyps denv.index_range (p_equal va vm) in + let cluster = cluster () in + Definitions.define_symbol { + d_lfun = lfun ; d_types = 0 ; + d_params = x :: denv.size_var @ xmem ; + d_definition = Logic result ; + d_cluster = cluster ; + } ; + Definitions.define_lemma { + l_assumed = true ; + l_name = axiom ; l_types = 0 ; + l_forall = F.p_vars lemma ; + l_triggers = [[Trigger.of_term va]] ; + l_lemma = lemma ; + l_cluster = cluster ; + } ; + if denv.monotonic then + begin + let ns = List.map F.e_var denv.size_var in + frame_lemmas lfun obj_a loc (v::ns) chunks + end ; + lfun , chunks + + let compile = Lang.local generate + end) + + (* -------------------------------------------------------------------------- *) + (* --- Loader --- *) + (* -------------------------------------------------------------------------- *) + + let load_comp sigma comp loc = + let r , p = M.to_region_pointer loc in + let f , m = COMP.get (r,comp) in + F.e_fun f (p :: memories sigma m) + + let load_array sigma a loc = + let d = Matrix.of_array a in + let r , p = M.to_region_pointer loc in + let f , m = ARRAY.get (r,a,d) in + F.e_fun f (p :: Matrix.size d @ memories sigma m) + + let loadvalue sigma obj loc = + match obj with + | C_int i -> M.load_int sigma i loc + | C_float f -> M.load_float sigma f loc + | C_pointer t -> snd @@ M.to_region_pointer @@ M.load_pointer sigma t loc + | C_comp c -> load_comp sigma c loc + | C_array a -> load_array sigma a loc + + let load sigma obj loc = + let open Sigs in + match obj with + | C_int i -> Val (M.load_int sigma i loc) + | C_float f -> Val (M.load_float sigma f loc) + | C_pointer t -> Loc (M.load_pointer sigma t loc) + | C_comp c -> Val (load_comp sigma c loc) + | C_array a -> Val (load_array sigma a loc) + + let () = loadrec := loadvalue + + (* -------------------------------------------------------------------------- *) + (* --- Havocs --- *) + (* -------------------------------------------------------------------------- *) + + let havoc_length s obj loc length = + let ps = ref [] in + Domain.iter + (fun chunk -> + let pre = Sigma.value s.pre chunk in + let post = Sigma.value s.post chunk in + let tau = Chunk.tau_of_chunk chunk in + let basename = Chunk.basename_of_chunk chunk ^ "_undef" in + let fresh = F.e_var (Lang.freshvar ~basename tau) in + let havoc = M.havoc obj loc ~length chunk ~fresh ~current:pre in + ps := Set(post,havoc) :: !ps + ) (M.domain obj loc) ; !ps + + let havoc seq obj loc = havoc_length seq obj loc F.e_one + + (* -------------------------------------------------------------------------- *) + (* --- Stored & Copied --- *) + (* -------------------------------------------------------------------------- *) + + let updated seq phi alpha loc value = + let chunk,mem = phi seq.pre alpha loc value in + [Set(Sigma.value seq.post chunk,mem)] + + let stored seq obj loc value = + match obj with + | C_int i -> updated seq M.store_int i loc value + | C_float f -> updated seq M.store_float f loc value + | C_pointer ty -> updated seq M.store_pointer ty loc value + | C_comp _ | C_array _ -> + Set(loadvalue seq.post obj loc, value) :: havoc seq obj loc + + let copied s obj p q = stored s obj p (loadvalue s.pre obj q) + + (* -------------------------------------------------------------------------- *) + (* --- Assigned --- *) + (* -------------------------------------------------------------------------- *) + + let assigned_loc seq obj loc = + match obj with + | C_int _ | C_float _ | C_pointer _ -> + let x = Lang.freshvar ~basename:"v" (Lang.tau_of_object obj) in + stored seq obj loc (e_var x) + | C_comp _ | C_array _ -> + havoc seq obj loc + + let assigned_range s obj l a b = + havoc_length s obj (M.shift l obj a) (e_range a b) + + let assigned seq obj = function + | Sloc loc -> assigned_loc seq obj loc + | Sdescr(xs,loc,condition) -> + let ps = ref [] in + Domain.iter + (fun c -> + let m1 = Sigma.value seq.pre c in + let m2 = Sigma.value seq.post c in + let p,separated,equal = M.eqmem_forall obj loc c m1 m2 in + let sep_from_all = F.p_forall xs (F.p_imply condition separated) in + let phi = F.p_forall p (F.p_imply sep_from_all equal) in + ps := Assert phi :: !ps + ) (M.domain obj loc) ; !ps + | Sarray(loc,obj,n) -> + assigned_range seq obj loc e_zero (e_int (n-1)) + | Srange(loc,obj,u,v) -> + let a = match u with Some a -> a | None -> e_zero in + let b = match v with Some b -> b | None -> M.last seq.pre obj loc in + assigned_range seq obj loc a b + + (* -------------------------------------------------------------------------- *) + +end diff --git a/src/plugins/wp/MemLoader.mli b/src/plugins/wp/MemLoader.mli new file mode 100644 index 0000000000000000000000000000000000000000..6f94c256955700557f6736215d5e40c72eacb6ae --- /dev/null +++ b/src/plugins/wp/MemLoader.mli @@ -0,0 +1,105 @@ +(**************************************************************************) +(* *) +(* This file is part of WP plug-in of Frama-C. *) +(* *) +(* Copyright (C) 2007-2019 *) +(* 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). *) +(* *) +(**************************************************************************) + +(* -------------------------------------------------------------------------- *) + +(** Compound Loader *) + +open Cil_types +open Definitions +open Ctypes +open Lang.F +open Sigs + +val cluster : unit -> cluster + +(** Frame Conditions. + Consider a function [phi(m)] over memory [m], + we want memories [m1,m2] and condition [p] such that + [p(m1,m2) -> phi(m1) = phi(m2)]. + - [name] used for generating lemma + - [triggers] for the lemma + - [conditions] for the frame lemma to hold + - [mem1,mem2] to two memories for which the lemma holds *) +type frame = string * Definitions.trigger list * pred list * term * term + +(** Loader Model for Atomic Values *) +module type Model = +sig + + module Chunk : Chunk + module Sigma : Sigma with type chunk = Chunk.t + + val name : string + + type loc + val sizeof : c_object -> int + val field : loc -> fieldinfo -> loc + val shift : loc -> c_object -> term -> loc + + (** Conversion among loc, t_pointer terms and t_addr terms *) + + val to_addr : loc -> term + val to_region_pointer : loc -> int * term + val of_region_pointer : int -> c_object -> term -> loc + + val domain : c_object -> loc -> Sigma.domain + val frames : c_object -> loc -> Chunk.t -> frame list + + val last : Sigma.t -> c_object -> loc -> term + + val havoc : c_object -> loc -> length:term -> + Chunk.t -> fresh:term -> current:term -> term + + val eqmem : c_object -> loc -> Chunk.t -> term -> term -> pred + + val eqmem_forall : + c_object -> loc -> Chunk.t -> term -> term -> var list * pred * pred + + val load_int : Sigma.t -> c_int -> loc -> term + val load_float : Sigma.t -> c_float -> loc -> term + val load_pointer : Sigma.t -> typ -> loc -> loc + + val store_int : Sigma.t -> c_int -> loc -> term -> Chunk.t * term + val store_float : Sigma.t -> c_float -> loc -> term -> Chunk.t * term + val store_pointer : Sigma.t -> typ -> loc -> term -> Chunk.t * term + +end + +(** Generates Loader for Compound Values *) +module Make (M : Model) : +sig + + val load : M.Sigma.t -> c_object -> M.loc -> M.loc Sigs.value + val loadvalue : M.Sigma.t -> c_object -> M.loc -> term + + val havoc : M.Sigma.t sequence -> c_object -> M.loc -> equation list + val havoc_length : M.Sigma.t sequence -> c_object -> M.loc -> term -> equation list + + val stored : M.Sigma.t sequence -> c_object -> M.loc -> term -> equation list + val copied : M.Sigma.t sequence -> c_object -> M.loc -> M.loc -> equation list + + val assigned : M.Sigma.t sequence -> c_object -> M.loc sloc -> equation list + +end + +(* -------------------------------------------------------------------------- *) diff --git a/src/plugins/wp/MemTyped.ml b/src/plugins/wp/MemTyped.ml index abb143b4dd2872da790be41d66b6c547d067f3bc..414d5f49fcf816bd1527a34e6482704930e20e5b 100644 --- a/src/plugins/wp/MemTyped.ml +++ b/src/plugins/wp/MemTyped.ml @@ -34,7 +34,6 @@ open Definitions let dkey_layout = Wp_parameters.register_category "layout" - module L = Qed.Logic let datatype = "MemTyped" diff --git a/src/plugins/wp/Sigs.ml b/src/plugins/wp/Sigs.ml index d451e04f15fcb2003abd1d85c6769e6a4afc1da0..6fc72a241aaea9e0a3f4c1e465d17c476d787977 100644 --- a/src/plugins/wp/Sigs.ml +++ b/src/plugins/wp/Sigs.ml @@ -135,6 +135,7 @@ sig type t val self : string (** Chunk names, for pretty-printing. *) val hash : t -> int + val equal : t -> t -> bool val compare : t -> t -> int val pretty : Format.formatter -> t -> unit