From ca39f059d00a22d1e95b75cca48fd36861fc3468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr> Date: Wed, 12 Jun 2024 08:54:26 +0200 Subject: [PATCH] [region] aliasing annotations & region labels --- .../src/frama-c/plugins/region/api/index.ts | 20 +-- ivette/src/frama-c/plugins/region/memory.tsx | 17 ++- src/plugins/region/annot.ml | 128 +++++++++--------- src/plugins/region/annot.mli | 32 ++--- src/plugins/region/code.ml | 71 ++++++---- src/plugins/region/logic.ml | 55 ++++++++ src/plugins/region/logic.mli | 27 ++++ src/plugins/region/memory.ml | 125 ++++++++++++----- src/plugins/region/memory.mli | 19 ++- src/plugins/region/services.ml | 5 + 10 files changed, 333 insertions(+), 166 deletions(-) create mode 100644 src/plugins/region/logic.ml create mode 100644 src/plugins/region/logic.mli diff --git a/ivette/src/frama-c/plugins/region/api/index.ts b/ivette/src/frama-c/plugins/region/api/index.ts index 122c71d9f67..8d4530d2f54 100644 --- a/ivette/src/frama-c/plugins/region/api/index.ts +++ b/ivette/src/frama-c/plugins/region/api/index.ts @@ -92,15 +92,16 @@ export const rangeDefault: range = { offset: 0, length: 0, cells: 0, data: nodeDefault }; export type region = - { node: node, roots: string[], parents: node[], sizeof: number, - ranges: range[], pointed?: node, reads: boolean, writes: boolean, - bytes: boolean, label: string, title: string }; + { node: node, roots: string[], labels: string[], parents: node[], + sizeof: number, ranges: range[], pointed?: node, reads: boolean, + writes: boolean, bytes: boolean, label: string, title: string }; /** Decoder for `region` */ export const jRegion: Json.Decoder<region> = Json.jObject({ node: jNode, roots: Json.jArray(Json.jString), + labels: Json.jArray(Json.jString), parents: Json.jArray(jNode), sizeof: Json.jNumber, ranges: Json.jArray(jRange), @@ -115,11 +116,12 @@ export const jRegion: Json.Decoder<region> = /** Natural order for `region` */ export const byRegion: Compare.Order<region> = Compare.byFields - <{ node: node, roots: string[], parents: node[], sizeof: number, - ranges: range[], pointed?: node, reads: boolean, writes: boolean, - bytes: boolean, label: string, title: string }>({ + <{ node: node, roots: string[], labels: string[], parents: node[], + sizeof: number, ranges: range[], pointed?: node, reads: boolean, + writes: boolean, bytes: boolean, label: string, title: string }>({ node: byNode, roots: Compare.array(Compare.alpha), + labels: Compare.array(Compare.alpha), parents: Compare.array(byNode), sizeof: Compare.number, ranges: Compare.array(byRange), @@ -133,9 +135,9 @@ export const byRegion: Compare.Order<region> = /** Default value for `region` */ export const regionDefault: region = - { node: nodeDefault, roots: [], parents: [], sizeof: 0, ranges: [], - pointed: undefined, reads: false, writes: false, bytes: false, label: '', - title: '' }; + { node: nodeDefault, roots: [], labels: [], parents: [], sizeof: 0, + ranges: [], pointed: undefined, reads: false, writes: false, + bytes: false, label: '', title: '' }; /** Region Analysis Updated */ export const updated: Server.Signal = { diff --git a/ivette/src/frama-c/plugins/region/memory.tsx b/ivette/src/frama-c/plugins/region/memory.tsx index 4e011695b5d..29c9b5a6341 100644 --- a/ivette/src/frama-c/plugins/region/memory.tsx +++ b/ivette/src/frama-c/plugins/region/memory.tsx @@ -55,8 +55,8 @@ function makeRecord( } interface Diagram { - nodes: Dot.Node[] ; - edges: Dot.Edge[] ; + nodes: Dot.Node[]; + edges: Dot.Edge[]; } function makeDiagram(regions: readonly Region.region[]): Diagram { @@ -76,8 +76,17 @@ function makeDiagram(regions: readonly Region.region[]): Diagram { const cells = makeRecord(edges, id, r.sizeof, r.ranges); const shape = cells.length > 0 ? cells : undefined; nodes.push({ id, font, color, label: r.label, title: r.title, shape }); + // --- Labels + const L: Dot.Node = + { id: '', shape: 'note', font: 'mono' }; + r.labels.forEach(a => { + const lid = `L${a}`; + nodes.push({ ...L, id: lid, label: `${a}:` }); + edges.push({ source: lid, target: id }); + }); // --- Roots - const R: Dot.Node = { id: '', shape: 'cds', font: 'mono', color: 'blue' }; + const R: Dot.Node = + { id: '', shape: 'cds', font: 'mono' }; r.roots.forEach(x => { const xid = `X${x}`; nodes.push({ ...R, id: xid, label: x }); @@ -106,7 +115,7 @@ export interface MemoryViewProps { } export function MemoryView(props: MemoryViewProps): JSX.Element { - const { regions=[], label, node } = props; + const { regions = [], label, node } = props; const diagram = React.useMemo(() => makeDiagram(regions), [regions]); if (label && node) addSelected(diagram, label, node); return <Dot.Diagram {...diagram} />; diff --git a/src/plugins/region/annot.ml b/src/plugins/region/annot.ml index fb873e3ee84..746ebcffad8 100644 --- a/src/plugins/region/annot.ml +++ b/src/plugins/region/annot.ml @@ -28,25 +28,25 @@ open Cil_datatype (* --- Region Specifications --- *) (* -------------------------------------------------------------------------- *) -type lpath = { +type path = { loc : location ; - ltype : typ ; - lnode : lnode ; + typ : typ ; + step: step ; } -and lnode = - | L_var of varinfo - | L_region of string - | L_addr of lpath - | L_star of lpath - | L_index of lpath - | L_shift of lpath - | L_field of lpath * fieldinfo - | L_cast of typ * lpath +and step = + | Var of varinfo + | Region of string + | AddrOf of path + | Star of path + | Index of path + | Shift of path + | Field of path * fieldinfo + | Cast of typ * path type region = { rname: string option ; - rpath: lpath list ; + rpath: path list ; } (* -------------------------------------------------------------------------- *) @@ -54,29 +54,29 @@ type region = { (* -------------------------------------------------------------------------- *) let atomic = function - | L_var _ | L_region _ | L_addr _ | L_star _ | L_index _ | L_field _ -> true - | L_shift _ | L_cast _ -> false - -let rec pp_lnode fmt = function - | L_var x -> Varinfo.pretty fmt x - | L_region a -> Format.pp_print_string fmt a - | L_field(p,f) -> pfield p f fmt - | L_index a -> Format.fprintf fmt "%a[..]" pp_latom a - | L_shift a -> Format.fprintf fmt "%a+(..)" pp_latom a - | L_star a -> Format.fprintf fmt "*%a" pp_latom a - | L_addr a -> Format.fprintf fmt "&%a" pp_latom a - | L_cast(t,a) -> Format.fprintf fmt "(%a)@,%a" Typ.pretty t pp_latom a + | Var _ | Region _ | AddrOf _ | Star _ | Index _ | Field _ -> true + | Shift _ | Cast _ -> false + +let rec pp_step fmt = function + | Var x -> Varinfo.pretty fmt x + | Region a -> Format.pp_print_string fmt a + | Field(p,f) -> pfield p f fmt + | Index a -> Format.fprintf fmt "%a[..]" pp_atom a + | Shift a -> Format.fprintf fmt "%a+(..)" pp_atom a + | Star a -> Format.fprintf fmt "*%a" pp_atom a + | AddrOf a -> Format.fprintf fmt "&%a" pp_atom a + | Cast(t,a) -> Format.fprintf fmt "(%a)@,%a" Typ.pretty t pp_atom a and pfield p fd fmt = - match p.lnode with - | L_star p -> Format.fprintf fmt "%a->%a" pp_latom p Fieldinfo.pretty fd - | _ -> Format.fprintf fmt "%a.%a" pp_latom p Fieldinfo.pretty fd + match p.step with + | Star p -> Format.fprintf fmt "%a->%a" pp_atom p Fieldinfo.pretty fd + | _ -> Format.fprintf fmt "%a.%a" pp_atom p Fieldinfo.pretty fd -and pp_latom fmt a = - if atomic a.lnode then pp_lnode fmt a.lnode - else Format.fprintf fmt "@[<hov 2>(%a)@]" pp_lnode a.lnode +and pp_atom fmt a = + if atomic a.step then pp_step fmt a.step + else Format.fprintf fmt "@[<hov 2>(%a)@]" pp_step a.step -and pp_lpath fmt a = pp_lnode fmt a.lnode +and pp_path fmt a = pp_step fmt a.step let pp_named fmt = function None -> () | Some a -> Format.fprintf fmt "%s: " a @@ -85,10 +85,10 @@ let pp_region fmt r = | [] -> Format.pp_print_string fmt "\null" | p::ps -> begin - Format.fprintf fmt "@[<hov 2>]" ; + Format.fprintf fmt "@[<hov 2>" ; pp_named fmt r.rname ; - pp_lpath fmt p ; - List.iter (Format.fprintf fmt ",@ %a" pp_lpath) ps ; + pp_path fmt p ; + List.iter (Format.fprintf fmt ",@ %a" pp_path) ps ; Format.fprintf fmt "@]" ; end @@ -96,7 +96,7 @@ let pp_regions fmt = function | [] -> Format.pp_print_string fmt "\null" | r::rs -> begin - Format.fprintf fmt "@[<hv 0>]" ; + Format.fprintf fmt "@[<hv 0>" ; pp_region fmt r ; List.iter (Format.fprintf fmt ",@ %a" pp_region) rs ; Format.fprintf fmt "@]" ; @@ -109,7 +109,7 @@ let pp_regions fmt = function type env = { context: Logic_typing.typing_context ; mutable named: string option ; - mutable paths: lpath list ; + mutable paths: path list ; mutable specs: region list ; } @@ -123,9 +123,9 @@ let getCompoundType env ~loc typ = let parse_name (env:env) ~loc x = try match env.context.find_var x with - | { lv_origin = Some v } -> { loc ; ltype = v.vtype ; lnode = L_var v } + | { lv_origin = Some v } -> { loc ; typ = v.vtype ; step = Var v } | _ -> error env ~loc "Variable '%s' is not a C-variable" x - with Not_found -> { loc ; ltype = TVoid [] ; lnode = L_region x } + with Not_found -> { loc ; typ = TVoid [] ; step = Region x } let parse_field env ~loc comp f = try List.find (fun fd -> fd.fname = f) (Option.value ~default:[] comp.cfields) @@ -138,7 +138,7 @@ let parse_lrange (env: env) (e : lexpr) = | _ -> error env ~loc:e.lexpr_loc "Unexpected index (use unspecified range only)" -let parse_ltype env ~loc t = +let parse_typ env ~loc t = let open Logic_typing in let g = env.context in let t = g.logic_type g loc g.pre_state t in @@ -152,52 +152,52 @@ let rec parse_lpath (env:env) (e: lexpr) = | PLvar x -> parse_name env ~loc x | PLunop( Ustar , p ) -> let lv = parse_lpath env p in - if Cil.isPointerType lv.ltype then - let te = Cil.typeOf_pointed lv.ltype in - { loc ; lnode = L_star lv ; ltype = te } + if Cil.isPointerType lv.typ then + let te = Cil.typeOf_pointed lv.typ in + { loc ; step = Star lv ; typ = te } else error env ~loc "Pointer-type expected for operator '&'" | PLunop( Uamp , p ) -> let lv = parse_lpath env p in - let ltype = TPtr( lv.ltype , [] ) in - { loc ; lnode = L_addr lv ; ltype } + let typ = TPtr( lv.typ , [] ) in + { loc ; step = AddrOf lv ; typ } | PLbinop( p , Badd , rg ) -> parse_lrange env rg ; - let { ltype } as lv = parse_lpath env p in - if Cil.isPointerType ltype then - { loc ; lnode = L_shift lv ; ltype = ltype } + let { typ } as lv = parse_lpath env p in + if Cil.isPointerType typ then + { loc ; step = Shift lv ; typ = typ } else - if Cil.isArrayType ltype then - let te = Cil.typeOf_array_elem ltype in - { loc ; lnode = L_shift lv ; ltype = TPtr(te,[]) } + if Cil.isArrayType typ then + let te = Cil.typeOf_array_elem typ in + { loc ; step = Shift lv ; typ = TPtr(te,[]) } else error env ~loc "Pointer-type expected for operator '+'" | PLdot( p , f ) -> let lv = parse_lpath env p in - let comp = getCompoundType env ~loc:lv.loc lv.ltype in + let comp = getCompoundType env ~loc:lv.loc lv.typ in let fd = parse_field env ~loc comp f in - { loc ; lnode = L_field(lv,fd) ; ltype = fd.ftype } + { loc ; step = Field(lv,fd) ; typ = fd.ftype } | PLarrow( p , f ) -> let sp = { lexpr_loc = loc ; lexpr_node = PLunop(Ustar,p) } in let pf = { lexpr_loc = loc ; lexpr_node = PLdot(sp,f) } in parse_lpath env pf | PLarrget( p , rg ) -> parse_lrange env rg ; - let { ltype } as lv = parse_lpath env p in - if Cil.isPointerType ltype then - let pointed = Cil.typeOf_pointed ltype in - let ls = { loc ; lnode = L_shift lv ; ltype } in - { loc ; lnode = L_star ls ; ltype = pointed } + let { typ } as lv = parse_lpath env p in + if Cil.isPointerType typ then + let pointed = Cil.typeOf_pointed typ in + let ls = { loc ; step = Shift lv ; typ } in + { loc ; step = Star ls ; typ = pointed } else - if Cil.isArrayType ltype then - let elt = Cil.typeOf_array_elem ltype in - { loc ; lnode = L_index lv ; ltype = elt } + if Cil.isArrayType typ then + let elt = Cil.typeOf_array_elem typ in + { loc ; step = Index lv ; typ = elt } else error env ~loc:lv.loc "Pointer or array type expected" | PLcast( t , a ) -> let lv = parse_lpath env a in - let ty = parse_ltype env ~loc t in - { loc ; lnode = L_cast(ty,lv) ; ltype = ty } + let ty = parse_typ env ~loc t in + { loc ; step = Cast(ty,lv) ; typ = ty } | _ -> error env ~loc "Unexpected expression for region spec" @@ -255,7 +255,7 @@ let () = Acsl_extension.register_behavior ~plugin:"region" "region" typecheck ~printer false ; Acsl_extension.register_code_annot - ~plugin:"region" "region" typecheck ~printer false ; + ~plugin:"region" "alias" typecheck ~printer false ; end diff --git a/src/plugins/region/annot.mli b/src/plugins/region/annot.mli index e460c86cb14..d820c8a741d 100644 --- a/src/plugins/region/annot.mli +++ b/src/plugins/region/annot.mli @@ -22,30 +22,30 @@ open Cil_types -type lpath = { +type path = { loc : location ; - ltype : typ ; - lnode : lnode ; + typ : typ ; + step: step ; } -and lnode = - | L_var of varinfo - | L_region of string - | L_addr of lpath - | L_star of lpath - | L_index of lpath - | L_shift of lpath - | L_field of lpath * fieldinfo - | L_cast of typ * lpath +and step = + | Var of varinfo + | Region of string + | AddrOf of path + | Star of path + | Index of path + | Shift of path + | Field of path * fieldinfo + | Cast of typ * path type region = { rname: string option ; - rpath: lpath list ; + rpath: path list ; } -val pp_lnode : Format.formatter -> lnode -> unit -val pp_latom : Format.formatter -> lpath -> unit -val pp_lpath : Format.formatter -> lpath -> unit +val pp_step : Format.formatter -> step -> unit +val pp_atom : Format.formatter -> path -> unit +val pp_path : Format.formatter -> path -> unit val pp_region : Format.formatter -> region -> unit val pp_regions : Format.formatter -> region list -> unit diff --git a/src/plugins/region/code.ml b/src/plugins/region/code.ml index b0231ead15f..26a8e0de778 100644 --- a/src/plugins/region/code.ml +++ b/src/plugins/region/code.ml @@ -24,11 +24,6 @@ open Cil_types open Cil_datatype open Memory -let typeof_array_elt ty = - match Cil.unrollType ty with - | TArray(te,_,_) -> te - | _ -> Cil.voidType - (* -------------------------------------------------------------------------- *) (* --- L-Values & Expressions --- *) (* -------------------------------------------------------------------------- *) @@ -38,25 +33,17 @@ let rec lval (m:map) (s:stmt) (lv:lval) : node = loffset m s (lhost m s h) (Cil.typeOfLhost h) (snd lv) and lhost (m:map) (s:stmt) = function - | Var x -> Memory.root m x + | Var x -> Memory.add_root m x | Mem e -> pointer m s e and loffset (m:map) (s:stmt) (r:node) (ty:typ)= function | NoOffset -> r | Field(fd,ofs) -> - let size = Cil.bitsSizeOf ty in - let offset, length = Cil.fieldBitsOffset fd in - let data = Memory.cell m () in - let rc = Memory.range m ~size ~offset ~length ~data in - ignore @@ Memory.merge m r rc ; loffset m s data fd.ftype ofs + loffset m s (add_field m r fd) fd.ftype ofs | Index(_,ofs) -> - let size = Cil.bitsSizeOf ty in - let te = typeof_array_elt ty in - let data = Memory.cell m () in - let rc = Memory.range m ~size ~offset:0 ~length:size ~data in - ignore @@ Memory.merge m r rc ; loffset m s data te ofs + loffset m s (add_index m r ty) (Cil.typeOf_array_elem ty) ofs -and pointer m s e = match exp m s e with None -> cell m () | Some r -> r +and pointer m s e = match exp m s e with None -> add_cell m () | Some r -> r and value m s e = ignore (exp m s e) @@ -70,12 +57,7 @@ and exp (m: map) (s:stmt) (e:exp) : node option = | Lval lv -> let rv = lval m s lv in Memory.read m rv (Lval(s,lv)) ; - if Cil.isPointerType @@ Cil.typeOfLval lv then - let rp = cell m () in - Memory.points_to m rv rp ; - Some rp - else - None + Memory.add_value m rv @@ Cil.typeOfLval lv | UnOp(_,e,_) -> value m s e ; None @@ -84,7 +66,7 @@ and exp (m: map) (s:stmt) (e:exp) : node option = value m s k ; let r = pointer m s p in (*TODO: move the 'A' access on the source of the pointed region *) - Memory.shift m r (Exp(s,p)) ; + (*Memory.shift m r (Exp(s,p)) ;*) Some r | BinOp(_,a,b,_) -> @@ -96,7 +78,7 @@ and exp (m: map) (s:stmt) (e:exp) : node option = if Cil.isPointerType ty then Some (pointer m s p) else - (value m s e ; None) + (value m s p ; None) | Const _ | SizeOf _ | SizeOfE _ | SizeOfStr _ @@ -113,7 +95,7 @@ let rec init (m:map) (s:stmt) (acs:Access.acs) (lv:lval) (iv:init) = | SingleInit e -> let r = lval m s lv in Memory.write m r acs ; - Option.iter (Memory.points_to m r) (exp m s e) + Option.iter (Memory.add_points_to m r) (exp m s e) | CompoundInit(_,fvs) -> List.iter @@ -134,7 +116,7 @@ let instr (m:map) (s:stmt) (instr:instr) = let r = lval m s lv in let v = exp m s e in Memory.write m r (Lval(s,lv)) ; - Option.iter (Memory.points_to m r) v + Option.iter (Memory.add_points_to m r) v | Local_init(x,AssignInit iv,_) -> let acs = Access.Init(s,x) in @@ -173,7 +155,7 @@ let rec stmt (r:rmap) (m:map) (s:stmt) = "Annotations not analyzed" ; match s.skind with | Instr ki -> instr m s ki ; store r m s - | Return(Some e,_) -> value m s e ; store r m s + | Return(Some e,_) -> value m s e ; store r m s | Goto _ | Break _ | Continue _ | Return(None,_) -> store r m s | If(e,st,se,_) -> value m s e ; @@ -207,6 +189,27 @@ and catch (r:rmap) (m:map) (c:catch_binder) = and block (r:rmap) (m:map) (b:block) = List.iter (stmt r m) b.bstmts +(* -------------------------------------------------------------------------- *) +(* --- Behavior --- *) +(* -------------------------------------------------------------------------- *) + +type imap = Memory.map Property.Map.t ref + +let istore imap m ip = + imap := Property.Map.add ip (Memory.copy ~locked:true m) !imap + +let bhv ~kf (s:imap) (m:map) (bhv:behavior) = + List.iter + (fun e -> + let rs = Annot.of_extension e in + if rs <> [] then + begin + List.iter (Logic.add_region m) rs ; + let ip = Property.ip_of_extended (ELContract kf) e in + istore s m ip ; + end + ) bhv.b_extended + (* -------------------------------------------------------------------------- *) (* --- Function --- *) (* -------------------------------------------------------------------------- *) @@ -220,15 +223,23 @@ type domain = { let domain ?global kf = let m = match global with Some g -> g | None -> Memory.create () in let r = ref Stmt.Map.empty in + let s = ref Property.Map.empty in + begin + try + let funspec = Annotations.funspec kf in + List.iter (bhv ~kf s m) funspec.spec_behavior ; + with Annotations.No_funspec _ -> () + end ; begin try let fundec = Kernel_function.get_definition kf in block r m fundec.sbody ; with Kernel_function.No_Definition -> () - end ; { + end ; + { map = Memory.copy ~locked:true m ; body = !r ; - spec = Property.Map.empty ; + spec = !s ; } (* -------------------------------------------------------------------------- *) diff --git a/src/plugins/region/logic.ml b/src/plugins/region/logic.ml new file mode 100644 index 00000000000..e46702c622e --- /dev/null +++ b/src/plugins/region/logic.ml @@ -0,0 +1,55 @@ +(**************************************************************************) +(* *) +(* This file is part of Frama-C. *) +(* *) +(* Copyright (C) 2007-2024 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* 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 Annot +open Memory + +let rec add_lval (m:map) (p:path): node = + match p.step with + | Var x -> add_root m x + | Region a -> add_label m a + | Field(lv,fd) -> Memory.add_field m (add_lval m lv) fd + | Index lv -> Memory.add_index m (add_lval m lv) lv.typ + | Star e | Cast(_,e) -> add_pointer m e + | Shift _ | AddrOf _ -> + Options.error ~source:(fst p.loc) + "Unexpected expression (l-value expected)" ; + Memory.add_cell m () +and add_pointer (m:map) (p:path): Memory.node = + match add_exp m p with + | None -> add_cell m () + | Some r -> r + +and add_exp (m:map) (p:path): Memory.node option = + match p.step with + | (Var _ | Field _ | Index _ | Star _ | Cast _ | Region _) -> + let r = add_lval m p in + add_value m r p.typ + | AddrOf p -> Some (add_lval m p) + | Shift p -> add_exp m p + +let add_region (m: map) (r : Annot.region) = + let rs = List.map (add_lval m) r.rpath in + merge_all m @@ + match r.rname with + | None -> rs + | Some a -> add_label m a :: rs diff --git a/src/plugins/region/logic.mli b/src/plugins/region/logic.mli new file mode 100644 index 00000000000..e5fb991d29a --- /dev/null +++ b/src/plugins/region/logic.mli @@ -0,0 +1,27 @@ +(**************************************************************************) +(* *) +(* This file is part of Frama-C. *) +(* *) +(* Copyright (C) 2007-2024 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* 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 Memory + +val add_lval : map -> Annot.path -> node +val add_exp : map -> Annot.path -> node option +val add_region : map -> Annot.region -> unit diff --git a/src/plugins/region/memory.ml b/src/plugins/region/memory.ml index 8ac0519149b..9bf73e527ba 100644 --- a/src/plugins/region/memory.ml +++ b/src/plugins/region/memory.ml @@ -24,6 +24,9 @@ open Cil_types open Cil_datatype module Ufind = UnionFind.Make(Store) module Vmap = Varinfo.Map +module Vset = Varinfo.Set +module Lmap = Map.Make(String) +module Lset = Set.Make(String) (* -------------------------------------------------------------------------- *) (* --- Region Maps --- *) @@ -40,7 +43,8 @@ and layout = and chunk = { cparents: node list ; - croots: varinfo list ; + croots: Vset.t ; + clabels: Lset.t ; creads: Access.Set.t ; cwrites: Access.Set.t ; cshifts: Access.Set.t ; @@ -52,7 +56,8 @@ type rg = node Ranges.range type map = { store: chunk Ufind.store ; mutable locked: bool ; - mutable index: node Vmap.t ; + mutable roots: node Vmap.t ; + mutable labels: node Lmap.t ; } (* -------------------------------------------------------------------------- *) @@ -101,7 +106,8 @@ let pp_chunk fmt (n: node) (m: chunk) = Format.fprintf fmt "@[<hov 2>%a: %c%c%c" pp_node n (acs 'R' m.creads) (acs 'W' m.cwrites) (acs 'A' m.cshifts) ; List.iter (Format.fprintf fmt "@ (%a)" Typ.pretty) (types m) ; - List.iter (Format.fprintf fmt "@ %a" Varinfo.pretty) m.croots ; + Lset.iter (Format.fprintf fmt "@ %s:") m.clabels ; + Vset.iter (Format.fprintf fmt "@ %a" Varinfo.pretty) m.croots ; if Options.debug_atleast 1 then begin Access.Set.iter (Format.fprintf fmt "@ R:%a" Access.pretty) m.creads ; @@ -119,18 +125,21 @@ let pp_chunk fmt (n: node) (m: chunk) = let create () = { locked = false ; store = Ufind.new_store () ; - index = Vmap.empty ; + roots = Vmap.empty ; + labels = Lmap.empty ; } let copy ?locked m = { locked = (match locked with None -> m.locked | Some l -> l) ; store = Ufind.copy m.store ; - index = m.index ; + roots = m.roots ; + labels = m.labels ; } let empty = { cparents = [] ; - croots = [] ; + croots = Vset.empty ; + clabels = Lset.empty ; creads = Access.Set.empty ; cwrites = Access.Set.empty ; cshifts = Access.Set.empty ; @@ -158,33 +167,40 @@ let get map node = (* --- Chunk Constructors --- *) (* -------------------------------------------------------------------------- *) -let cell (m: map) ?size ?ptr ?root () = - failwith_locked m "Region.Memory.cell" ; +let add_cell (m: map) ?size ?ptr ?root ?label () = + failwith_locked m "Region.Memory.add_cell" ; let clayout = match size, ptr with | None, None -> Blob | None, Some _ -> Cell(Cil.bitsSizeOf Cil.voidPtrType,ptr) | Some s, _ -> Cell(s,ptr) in - let croots = match root with None -> [] | Some v -> [v] in - Ufind.make m.store { empty with clayout ; croots } + let croots = Vset.(match root with None -> empty | Some v -> singleton v) in + let clabels = Lset.(match label with None -> empty | Some a -> singleton a) in + Ufind.make m.store { empty with clayout ; croots ; clabels } let update (m: map) (n: node) (f: chunk -> chunk) = let r = get m n in Ufind.set m.store n (f r) -let range (m: map) ~size ~offset ~length ~data : node = - failwith_locked m "Region.Memory.range" ; +let add_range (m: map) ~size ~offset ~length ~data : node = + failwith_locked m "Region.Memory.add_range" ; let last = offset + length in if not (0 <= offset && offset < last && last <= size) then - raise (Invalid_argument "Region.Memory.range") ; + raise (Invalid_argument "Region.Memory.add_range") ; let clayout = Compound(size, Ranges.singleton { offset ; length ; data }) in let n = Ufind.make m.store { empty with clayout } in update m data (fun r -> { r with cparents = nodes m @@ n :: r.cparents }) ; n -let root (m: map) v = - try Vmap.find v m.index with Not_found -> - failwith_locked m "Region.Memory.root" ; - let n = cell m ~root:v () in - m.index <- Vmap.add v n m.index ; n +let add_root (m: map) v = + try Vmap.find v m.roots with Not_found -> + failwith_locked m "Region.Memory.add_root" ; + let n = add_cell m ~root:v () in + m.roots <- Vmap.add v n m.roots ; n + +let add_label (m: map) a = + try Lmap.find a m.labels with Not_found -> + failwith_locked m "Region.Memory.add_label" ; + let n = add_cell m ~label:a () in + m.labels <- Lmap.add a n m.labels ; n (* -------------------------------------------------------------------------- *) (* --- Iterator --- *) @@ -201,6 +217,7 @@ type region = { node: node ; parents: node list ; roots: varinfo list ; + labels: string list ; types: typ list ; reads: Access.acs list ; writes: Access.acs list ; @@ -220,11 +237,12 @@ let pp_region fmt (m: region) = Format.fprintf fmt "@[<hov 2>%a: %c%c%c" pp_node m.node (acs 'R' m.reads) (acs 'W' m.writes) (acs 'A' m.shifts) ; - List.iter (Format.fprintf fmt "@ (%a)" Typ.pretty) m.types ; + List.iter (Format.fprintf fmt "@ %s:") m.labels ; List.iter (Format.fprintf fmt "@ %a" Varinfo.pretty) m.roots ; + List.iter (Format.fprintf fmt "@ (%a)" Typ.pretty) m.types ; Format.fprintf fmt "@ %db" m.sizeof ; Option.iter (Format.fprintf fmt "@ (*%a)" pp_node) m.pointed ; - Format.fprintf fmt "@[<hv 0>]" ; + Format.fprintf fmt "@[<hv 0>" ; List.iter (Format.fprintf fmt "@ %a" pp_range) m.ranges ; Format.fprintf fmt "@]" ; if Options.debug_atleast 1 then @@ -246,7 +264,8 @@ let make_range (m: map) (rg: rg) : range = { let make_region (m: map) (n: node) (r: chunk) : region = { node = n ; parents = nodes m r.cparents ; - roots = r.croots ; + roots = Vset.elements r.croots ; + labels = Lset.elements r.clabels ; reads = Access.Set.elements r.creads ; writes = Access.Set.elements r.cwrites ; shifts = Access.Set.elements r.cshifts ; @@ -272,7 +291,7 @@ let rec walk h m f n = let iter (m:map) (f: region -> unit) = let h = Hashtbl.create 0 in - Vmap.iter (fun _x n -> walk h m f n) m.index + Vmap.iter (fun _x n -> walk h m f n) m.roots let regions map = let pool = ref [] in @@ -311,7 +330,7 @@ let merge_range (m: map) (q: queue) (ra : rg) (rb : rg) : node = let size = Ranges.(sa %. sb %. dp %. dq) in let data = merge_node m q na nb in if size = sa && size = sb then data else - merge_node m q (cell m ~size ()) data + merge_node m q (add_cell m ~size ()) data let merge_ranges (m: map) (q: queue) (sa : int) (wa : node Ranges.t) @@ -338,13 +357,14 @@ let merge_layout (m: map) (q: queue) (a : layout) (b : layout) : layout = Compound(size, singleton ~size @@ Ranges.squash (merge_node m q) wr) | Compound(sr,wr), Cell(sx,Some ptr) | Cell(sx,Some ptr), Compound(sr,wr) -> - let rp = cell m ~size:sx ~ptr () in + let rp = add_cell m ~size:sx ~ptr () in let wx = Ranges.range ~length:sx rp in merge_ranges m q sx wx sr wr let merge_region (m: map) (q: queue) (a : chunk) (b : chunk) : chunk = { cparents = nodes m @@ Store.bag a.cparents b.cparents ; - croots = List.sort_uniq Varinfo.compare @@ Store.bag a.croots b.croots ; + clabels = Lset.union a.clabels b.clabels ; + croots = Vset.union a.croots b.croots ; creads = Access.Set.union a.creads b.creads ; cwrites = Access.Set.union a.cwrites b.cwrites ; cshifts = Access.Set.union a.cshifts b.cshifts ; @@ -360,16 +380,51 @@ let do_merge (m: map) (q: queue) (a: node) (b: node): unit = Ufind.set m.store rx rc ; end -let merge (m: map) (a: node) (b: node) : node = - failwith_locked m "Region.Memory.merge" ; - if Ufind.eq m.store a b then Ufind.find m.store a else +let merge_all (m:map) = function + | [] -> () + | r::rs -> let q = Queue.create () in - do_merge m q a b ; + List.iter (fun r' -> ignore @@ merge_node m q r r') rs ; while not @@ Queue.is_empty q do let a,b = Queue.pop q in do_merge m q a b ; - done ; - Ufind.find m.store a + done + +let merge (m: map) (a: node) (b: node) : node = + failwith_locked m "Region.Memory.merge" ; + merge_all m [a;b] ; Ufind.find m.store (min a b) + +(* -------------------------------------------------------------------------- *) +(* --- Offset --- *) +(* -------------------------------------------------------------------------- *) + +let add_field (m:map) (r:node) (fd:fieldinfo) : node = + let ci = fd.fcomp in + if ci.cstruct then + let size = Cil.bitsSizeOf (TComp(ci,[])) in + let offset, length = Cil.fieldBitsOffset fd in + let data = add_cell m () in + let rc = add_range m ~size ~offset ~length ~data in + ignore @@ merge m r rc ; data + else r + +let add_index (m:map) (r:node) (ty:typ) : node = + let size = Cil.bitsSizeOf ty in + let data = add_cell m () in + let rc = add_range m ~size ~offset:0 ~length:size ~data in + ignore @@ merge m r rc ; data + +let add_points_to (m: map) (a: node) (b : node) = + failwith_locked m "Region.Memory.points_to" ; + ignore @@ merge m a @@ add_cell m ~ptr:b () + +let add_value (m:map) (rv:node) (ty:typ) : node option = + if Cil.isPointerType ty then + let rp = add_cell m () in + add_points_to m rv rp ; + Some rp + else + None (* -------------------------------------------------------------------------- *) (* --- Access --- *) @@ -378,11 +433,7 @@ let merge (m: map) (a: node) (b: node) : node = let access (m:map) (a:node) (ty: typ) = let sr = sizeof (get m a).clayout in let size = Ranges.gcd sr (Cil.bitsSizeOf ty) in - if sr <> size then ignore (merge m a (cell m ~size ())) - -let points_to (m: map) (a: node) (b : node) = - failwith_locked m "Region.Memory.points_to" ; - ignore @@ merge m a @@ cell m ~ptr:b () + if sr <> size then ignore (merge m a (add_cell m ~size ())) let read (m: map) (a: node) from = failwith_locked m "Region.Memory.read" ; @@ -424,7 +475,7 @@ let rec lval (m: map) (lv: lval) : node = and host (m: map) (h: lhost) : node = match h with - | Var x -> Ufind.find m.store @@ Vmap.find x m.index + | Var x -> Ufind.find m.store @@ Vmap.find x m.roots | Mem e -> match exp m e with | None -> raise Not_found diff --git a/src/plugins/region/memory.mli b/src/plugins/region/memory.mli index d31f9bcfa71..79a0543ef0d 100644 --- a/src/plugins/region/memory.mli +++ b/src/plugins/region/memory.mli @@ -35,6 +35,7 @@ type region = { node: node ; parents: node list ; roots: varinfo list ; + labels: string list ; types: typ list ; reads: Access.acs list ; writes: Access.acs list ; @@ -62,10 +63,6 @@ val lock : map -> unit (** Unlock the map. *) val unlock : map -> unit -val root : map -> Cil_types.varinfo -> node -val cell : map -> ?size:int -> ?ptr:node -> ?root:varinfo -> unit -> node -val range : map -> size:int -> offset:int -> length:int -> data:node -> node - val id : node -> int val forge : int -> node val node : map -> node -> node @@ -75,11 +72,21 @@ val iter : map -> (region -> unit) -> unit val region : map -> node -> region val regions : map -> region list -val merge : map -> node -> node -> node +val add_root : map -> Cil_types.varinfo -> node +val add_label : map -> string -> node +val add_cell : map -> ?size:int -> ?ptr:node -> ?root:varinfo -> ?label:string -> unit -> node +val add_range : map -> size:int -> offset:int -> length:int -> data:node -> node +val add_field : map -> node -> fieldinfo -> node +val add_index : map -> node -> typ -> node +val add_points_to : map -> node -> node -> unit +val add_value : map -> node -> typ -> node option + val read : map -> node -> Access.acs -> unit val write : map -> node -> Access.acs -> unit val shift : map -> node -> Access.acs -> unit -val points_to : map -> node -> node -> unit + +val merge : map -> node -> node -> node +val merge_all : map -> node list -> unit (** @raise Not_found *) val lval : map -> lval -> node diff --git a/src/plugins/region/services.ml b/src/plugins/region/services.ml index 72d94683a11..0b5ab56eeec 100644 --- a/src/plugins/region/services.ml +++ b/src/plugins/region/services.ml @@ -71,6 +71,9 @@ struct let open Cil_types in Json.of_list @@ List.map (fun v -> Json.of_string v.vname) vs + let labels_to_json ls = + Json.of_list @@ List.map Json.of_string ls + let ikind_to_char (ikind : Cil_types.ikind) = match ikind with | IBool | IUChar -> 'b' @@ -141,6 +144,7 @@ struct Jrecord [ "node", Node.jtype ; "roots", Jarray Jalpha ; + "labels", Jarray Jalpha ; "parents", NodeList.jtype ; "sizeof", Jnumber ; "ranges", Ranges.jtype ; @@ -156,6 +160,7 @@ struct Json.of_fields [ "node", Node.to_json m.node ; "roots", roots_to_json m.roots ; + "labels", labels_to_json m.labels ; "parents", NodeList.to_json m.parents ; "sizeof", Json.of_int @@ m.sizeof ; "ranges", Ranges.to_json @@ m.ranges ; -- GitLab