From f5a59c116bdaec10018e4a69546edc55fa86271a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr> Date: Tue, 11 Jun 2024 16:44:52 +0200 Subject: [PATCH] [region] region annotations --- src/plugins/region/annot.ml | 257 +++++++++++++++++++++++++++++++++++ src/plugins/region/annot.mli | 53 ++++++++ 2 files changed, 310 insertions(+) create mode 100644 src/plugins/region/annot.ml create mode 100644 src/plugins/region/annot.mli diff --git a/src/plugins/region/annot.ml b/src/plugins/region/annot.ml new file mode 100644 index 00000000000..ef71d881aad --- /dev/null +++ b/src/plugins/region/annot.ml @@ -0,0 +1,257 @@ +(**************************************************************************) +(* *) +(* 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 Logic_ptree +open Cil_types +open Cil_datatype + +(* -------------------------------------------------------------------------- *) +(* --- Region Specifications --- *) +(* -------------------------------------------------------------------------- *) + +type lpath = { + loc : location ; + ltype : typ ; + lnode : lnode ; +} + +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 + +type region = { + rname: string option ; + rpath: lpath list ; +} + +(* -------------------------------------------------------------------------- *) +(* --- Printers --- *) +(* -------------------------------------------------------------------------- *) + +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 + +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 + +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_lpath fmt a = pp_lnode fmt a.lnode + +let pp_named fmt = function None -> () | Some a -> Format.fprintf fmt "%s: " a + +let pp_region fmt r = + match r.rpath with + | [] -> Format.pp_print_string fmt "\null" + | p::ps -> + begin + Format.fprintf fmt "@[<hov 2>]" ; + pp_named fmt r.rname ; + pp_lpath fmt p ; + List.iter (Format.fprintf fmt ",@ %a" pp_lpath) ps ; + Format.fprintf fmt "@]" ; + end + +let pp_regions fmt = function + | [] -> Format.pp_print_string fmt "\null" + | r::rs -> + begin + Format.fprintf fmt "@[<hv 0>]" ; + pp_region fmt r ; + List.iter (Format.fprintf fmt ",@ %a" pp_region) rs ; + Format.fprintf fmt "@]" ; + end + +(* -------------------------------------------------------------------------- *) +(* --- Parsers --- *) +(* -------------------------------------------------------------------------- *) + +type env = { + context: Logic_typing.typing_context ; + mutable named: string option ; + mutable paths: lpath list ; + mutable specs: region list ; +} + +let error (env:env) ~loc msg = env.context.error loc msg + +let getCompoundType env ~loc typ = + match Cil.unrollType typ with + | TComp(comp,_) -> comp + | _ -> error env ~loc "Expected compound type for term" + +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 } + | _ -> error env ~loc "Variable '%s' is not a C-variable" x + with Not_found -> { loc ; ltype = TVoid [] ; lnode = L_region x } + +let parse_field env ~loc comp f = + try List.find (fun fd -> fd.fname = f) (Option.value ~default:[] comp.cfields) + with Not_found -> + error env ~loc "No field '%s' in compound type '%s'" f comp.cname + +let parse_lrange (env: env) (e : lexpr) = + match e.lexpr_node with + | PLrange(None,None) -> () + | _ -> + error env ~loc:e.lexpr_loc "Unexpected index (use unspecified range only)" + +let parse_ltype 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 + match Logic_utils.unroll_type t with + | Ctype typ -> typ + | _ -> error env ~loc "C-type expected for casting l-values" + +let rec parse_lpath (env:env) (e: lexpr) = + let loc = e.lexpr_loc in + match e.lexpr_node with + | 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 } + 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 } + | 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 } + else + if Cil.isArrayType ltype then + let te = Cil.typeOf_array_elem ltype in + { loc ; lnode = L_shift lv ; ltype = 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 fd = parse_field env ~loc comp f in + { loc ; lnode = L_field(lv,fd) ; ltype = 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 } + else + if Cil.isArrayType ltype then + let elt = Cil.typeOf_array_elem ltype in + { loc ; lnode = L_index lv ; ltype = 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 } + | _ -> + error env ~loc "Unexpected expression for region spec" + +let rec parse_named_lpath (env:env) p = + match p.lexpr_node with + | PLnamed( name , p ) -> + if env.named <> None && env.paths <> [] then + begin + env.specs <- { rname = env.named ; rpath = env.paths } :: env.specs ; + env.paths <- [] ; + end ; + env.named <- Some name ; + parse_named_lpath env p + | _ -> + let path = parse_lpath env p in + env.paths <- path :: env.paths + +(* -------------------------------------------------------------------------- *) +(* --- Spec Typechecking & Printing --- *) +(* -------------------------------------------------------------------------- *) + +let kspec = ref 0 +let registry = Hashtbl.create 0 + +let of_extid = Hashtbl.find registry +let of_extrev = function + | { ext_name="region" ; ext_kind = Ext_id k } -> of_extid k + | _ -> raise Not_found +let of_extension e = List.rev (of_extrev e) +let of_behavior bhv = + List.fold_left + (fun acc e -> List.rev_append (try of_extrev e with Not_found -> []) acc) + [] bhv.Cil_types.b_extended + +let typecheck typing_context _loc ps = + let env = { + named = None ; + context = typing_context ; + paths = [] ; specs = [] ; + } in + List.iter (parse_named_lpath env) ps ; + let id = !kspec in incr kspec ; + let specs = { rname = env.named ; rpath = env.paths } :: env.specs in + Hashtbl.add registry id @@ List.rev specs ; + Ext_id id + +let printer _pp fmt = function + | Ext_id k -> + let rs = try Hashtbl.find registry k with Not_found -> [] in + pp_regions fmt rs + | _ -> () + +let () = + Acsl_extension.register_behavior + ~plugin:"region" "alias" typecheck ~printer false + +(* -------------------------------------------------------------------------- *) diff --git a/src/plugins/region/annot.mli b/src/plugins/region/annot.mli new file mode 100644 index 00000000000..daea818874d --- /dev/null +++ b/src/plugins/region/annot.mli @@ -0,0 +1,53 @@ +(**************************************************************************) +(* *) +(* 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 Cil_types + +type lpath = { + loc : location ; + ltype : typ ; + lnode : lnode ; +} + +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 + +type region = { + rname: string option ; + rpath: lpath list ; +} + +val pp_lnode : Format.formatter -> lnode -> unit +val pp_latom : Format.formatter -> lpath -> unit +val pp_lpath : Format.formatter -> lpath -> unit +val pp_region : Format.formatter -> region -> unit +val pp_regions : Format.formatter -> region list -> unit + +val of_extension : acsl_extension -> region list +val of_behavior : behavior -> region list -- GitLab