From 2026bf6788e059b1a9b29400e5261e4fff3956a0 Mon Sep 17 00:00:00 2001 From: Valentin Perrelle <valentin.perrelle@cea.fr> Date: Fri, 15 Apr 2022 16:40:36 +0200 Subject: [PATCH] [Eva] multidim: renaming and reorganization --- .../value/domains/multidim/multidim_domain.ml | 183 +++++++++--------- 1 file changed, 92 insertions(+), 91 deletions(-) diff --git a/src/plugins/value/domains/multidim/multidim_domain.ml b/src/plugins/value/domains/multidim/multidim_domain.ml index f1c9fe31572..1e6bf9c0d25 100644 --- a/src/plugins/value/domains/multidim/multidim_domain.ml +++ b/src/plugins/value/domains/multidim/multidim_domain.ml @@ -316,34 +316,27 @@ struct Memory.segmentation_hint ~oracle m loc bounds end -(* References to variables inside array segmentation. - For instance if an array A is described with the segmentation - 0..i-1 ; i ; i+1..10 - then, everytime i is changed, the segmentation must be updated. This requires - referencing every base where at least one segmentation references i. *) -module References = -struct - include Base.Hptset (* The set of bases referencing the variable *) -end - -module TrackedBases = -struct - include Base.Hptset -end - module DomainLattice = struct open Bottom.Operators + (* References to variables inside array segmentation. + For instance if an array A is described with the segmentation + 0..i-1 ; i ; i+1..10 + then, everytime i is changed, the segmentation must be updated. This requires + referencing every base where at least one segmentation references i. *) + module Referers = Base.Hptset (* The set of bases referencing the variable *) + (* The domain can be set to track a subset of bases *) + module Tracking = Base.Hptset (* The domain is essentially a map from bases to individual memory abstractions *) module Initial_Values = struct let v = [[]] end module Deps = struct let l = [Ast.self] end module V = struct - include Datatype.Pair (Memory) (References) + include Datatype.Pair (Memory) (Referers) let pretty_debug = pretty - let top = Memory.top, References.empty - let is_top (m,r) = Memory.is_top m && References.is_empty r + let top = Memory.top, Referers.empty + let is_top (m,r) = Memory.is_top m && Referers.is_empty r end module BaseMap = @@ -371,7 +364,7 @@ struct include Datatype.Pair_with_collections (BaseMap) - (Datatype.Option (TrackedBases)) + (Datatype.Option (Tracking)) (struct let module_name = "DomainLattice" end) type state = t @@ -391,18 +384,72 @@ struct (* Bases handling *) - let covers_base (tracked : TrackedBases.t option) (b : base) : bool = + let covers_base (tracked : Tracking.t option) (b : base) : bool = match b with | Base.Var (vi, _) | Allocated (vi, _, _) -> not (Cil.typeHasQualifier "volatile" vi.vtype) && - Option.fold ~none:true ~some:(TrackedBases.mem b) tracked + Option.fold ~none:true ~some:(Tracking.mem b) tracked | Null -> true | CLogic_Var _ | String _ -> false let join_tracked tracked1 tracked2 = match tracked1, tracked2 with | None, tracked | tracked, None -> tracked - | Some s1, Some s2 -> Some (TrackedBases.union s1 s2) + | Some s1, Some s2 -> Some (Tracking.union s1 s2) + + + (* References *) + + let add_references (state : t) (referee : base) (referers' : base list) : t = + let base_map, tracked = state in + let memory, referers = BaseMap.find_or_top base_map referee in + let referers'' = Referers.union referers (Referers.of_list referers') in + BaseMap.add referee (memory, referers'') base_map, tracked + + let add_references_l state (referees : base list) (referers : base list) = + List.fold_left + (fun state b -> add_references state b referers) + state referees + + let update_references ~oracle (dst : Cil_types.varinfo) + (src : Cil_types.exp option) (base_map,tracked : t) = + let incr = Option.bind src (fun expr -> + match expr.Cil_types.enode with + | BinOp ((PlusA|PlusPI), { enode=Lval (Var vi', NoOffset) }, exp, _typ) + when Cil_datatype.Varinfo.equal dst vi' -> + Cil.constFoldToInt exp + | BinOp ((PlusA|PlusPI), exp, { enode=Lval (Var vi', NoOffset)}, _typ) + when Cil_datatype.Varinfo.equal dst vi' -> + Cil.constFoldToInt exp + | BinOp ((MinusA|MinusPI), { enode=Lval (Var vi', NoOffset) }, exp, _typ) + when Cil_datatype.Varinfo.equal dst vi' -> + Option.map Integer.neg (Cil.constFoldToInt exp) + | _ -> None) + in + (* [oracle] must be the oracle before the (non-invertible) + assignement of the referee to allow removing of eventual empty slice + before the bound leaves the segmentation. *) + let referers = snd (BaseMap.find_or_top base_map (Base.of_varinfo dst)) in + let update_ref base base_map = + let update (memory, refs) = + let oracle = convert_oracle oracle in + Memory.incr_bound ~oracle dst incr memory, refs + in + BaseMap.replace (Option.map update) base base_map + in + let base_map = Referers.fold update_ref referers base_map in + (* If increment is None, every reference to dst should have been removed by + Memory.incr_bound *) + let base_map = + if Option.is_none incr then + BaseMap.replace + (Option.map (fun (memory, _refs) -> memory, Referers.empty)) + (Base.of_varinfo dst) + base_map + else + base_map + in + base_map, tracked (* Accesses *) @@ -469,26 +516,17 @@ struct let oracle = convert_oracle oracle in read (Memory.extract ~oracle) (Memory.smash ~oracle) state src - let add_references (base_map,tracked : t) vi refs' : t = - let base = Base.of_varinfo vi in - let memory, refs = BaseMap.find_or_top base_map base in - let refs'' = References.union refs (References.of_list refs') in - BaseMap.add base (memory, refs'') base_map, tracked - - let add_references_l state l refs = - List.fold_left (fun state vi -> add_references state vi refs) state l - let write' (update : memory -> offset -> memory or_bottom) (state : state) (loc : mdlocation) : state or_bottom = - let deps = Location.references loc in - let deps_set = TrackedBases.of_list (List.map Base.of_varinfo deps) in + let deps = List.map Base.of_varinfo (Location.references loc) in + let deps_set = Tracking.of_list deps in let f base off state' = let* base_map,tracked = state' in if covers_base tracked base then let memory, refs = BaseMap.find_or_top base_map base in let+ memory' = update memory off in BaseMap.add base (memory', refs) base_map, - Option.map (TrackedBases.union deps_set) tracked + Option.map (Tracking.union deps_set) tracked else state' in @@ -559,7 +597,7 @@ struct and decide _ x1 x2 = let m1,r1 = Option.value ~default:V.top x1 and m2,r2 = Option.value ~default:V.top x2 in - Memory.join ~oracle m1 m2, References.union r1 r2 (* TODO: Remove tops *) + Memory.join ~oracle m1 m2, Referers.union r1 r2 (* TODO: Remove tops *) in generic_join ~cache ~symmetric:false ~idempotent:true ~decide m1 m2, join_tracked t1 t2 @@ -576,7 +614,7 @@ struct and decide base x1 x2 = let m1,r1 = Option.value ~default:V.top x1 and m2,r2 = Option.value ~default:V.top x2 in - Memory.widen ~oracle (get_hints base) m1 m2, References.union r1 r2 + Memory.widen ~oracle (get_hints base) m1 m2, Referers.union r1 r2 in generic_join ~cache ~symmetric:false ~idempotent:true ~decide m1 m2, join_tracked t1 t2 @@ -647,55 +685,6 @@ struct let update valuation state = assume_valuation valuation state - let update_array_segmentation_bounds ~oracle vi expr (base_map,tracked) = - let incr = Option.bind expr (fun expr -> - match expr.Cil_types.enode with - | BinOp ((PlusA|PlusPI), { enode=Lval (Var vi', NoOffset) }, exp, _typ) - when Cil_datatype.Varinfo.equal vi vi' -> - Cil.constFoldToInt exp - | BinOp ((PlusA|PlusPI), exp, { enode=Lval (Var vi', NoOffset)}, _typ) - when Cil_datatype.Varinfo.equal vi vi' -> - Cil.constFoldToInt exp - | BinOp ((MinusA|MinusPI), { enode=Lval (Var vi', NoOffset) }, exp, _typ) - when Cil_datatype.Varinfo.equal vi vi' -> - Option.map Integer.neg (Cil.constFoldToInt exp) - | _ -> None) - in - (* Very important : oracle must be the oracle before a non-invertible - assignement of the bound to allow removing of eventual empty slice - before the bound leaves the segmentation. *) - let references = snd (BaseMap.find_or_top base_map (Base.of_varinfo vi)) in - let update_ref base base_map = - let update (memory, refs) = - let oracle = convert_oracle oracle in - Memory.incr_bound ~oracle vi incr memory, refs - in - BaseMap.replace (Option.map update) base base_map - in - let base_map = References.fold update_ref references base_map in - (* If increment is None, every reference to vi should have been removed by - Memory.incr_bound *) - let base_map = - if Option.is_none incr then - BaseMap.replace - (Option.map (fun (memory, _refs) -> memory, References.empty)) - (Base.of_varinfo vi) - base_map - else - base_map - in - base_map, tracked - - let update_array_segmentation ~oracle lval expr state = - match lval with - | Mem _, _ -> state (* Do nothing *) - | Var vi, offset -> - let expr = match offset with - | NoOffset -> expr - | _ -> None - in - update_array_segmentation_bounds ~oracle vi expr state - let assign_lval lval assigned_value oracle state = match Location.of_lval oracle lval with | `Top -> top @@ -712,9 +701,20 @@ struct overwrite ~oracle state dst src let assign _kinstr left expr assigned_value valuation state = - let oracle = valuation_to_oracle state valuation in - let state = update_array_segmentation ~oracle left.lval (Some expr) state in let+ state = assume_valuation valuation state in + let oracle = valuation_to_oracle state valuation in + (* Update references *) + let state = + match left.lval with + | Mem _, _ -> state (* Do nothing *) + | Var vi, offset -> + let expr = match offset with + | NoOffset -> Some expr + | _ -> None + in + update_references ~oracle vi expr state + in + (* Update destination *) assign_lval left.lval assigned_value oracle state let assume _stmt _expr _pos valuation state = @@ -763,7 +763,7 @@ struct let oracle = mk_oracle state in let state = List.fold_left - (fun state vi -> update_array_segmentation_bounds ~oracle vi None state) + (fun state vi -> update_references ~oracle vi None state) state vars in let (base_map,tracked) = state in @@ -831,15 +831,16 @@ struct (Cil_datatype.Varinfo.Set.to_seq r |> List.of_seq) @ acc in let references = List.fold_left add [] bounds in + let references = List.map Base.of_varinfo references in add_references_l state references (Location.bases loc) end | "eva_domain_scope" -> let domain,vars = Eva_annotations.read_domain_scope extension in if domain = "multidim" then let (base_map,tracked) = state in - let set = Option.value ~default:TrackedBases.empty tracked + let set = Option.value ~default:Tracking.empty tracked and bases = List.map Base.of_varinfo vars in - let tracked = List.fold_right TrackedBases.add bases set in + let tracked = List.fold_right Tracking.add bases set in let base_map = BaseMap.inter_with_shape tracked base_map in (* Only keep tracked bases in the current base map *) base_map, Some tracked else @@ -872,7 +873,7 @@ struct let filter _kf _kind bases (base_map,tracked : t) = BaseMap.filter (fun elt -> Base.Hptset.mem elt bases) base_map, - Option.map (TrackedBases.inter bases) tracked + Option.map (Tracking.inter bases) tracked let reuse _kf bases = let open BaseMap in -- GitLab