diff --git a/src/kernel_services/abstract_interp/abstract_memory.ml b/src/kernel_services/abstract_interp/abstract_memory.ml index d11f76492427d9cbd278f23d8817bf98fdea28b6..cbe6c0290882f4b68d2036bcce074358e61f93f5 100644 --- a/src/kernel_services/abstract_interp/abstract_memory.ml +++ b/src/kernel_services/abstract_interp/abstract_memory.ml @@ -314,10 +314,10 @@ sig val join : oracle:bioracle -> t -> t -> t val smash : oracle:oracle -> t -> t -> t val read : oracle:oracle -> (Cil_types.typ -> t -> 'a) -> ('a -> 'a -> 'a) -> - Abstract_offset.typed_offset -> t -> 'a + Abstract_offset.t -> t -> 'a val write : oracle:oracle -> (weak:bool -> Cil_types.typ -> t -> t or_bottom) -> - weak:bool -> Abstract_offset.typed_offset -> t -> t or_bottom + weak:bool -> Abstract_offset.t -> t -> t or_bottom val incr_bound : oracle:oracle -> Cil_types.varinfo -> Integer.t option -> t -> t val add_segmentation_bounds : oracle:oracle -> typ:Cil_types.typ -> @@ -1873,7 +1873,7 @@ struct include ProtoMemory - type location = Abstract_offset.typed_offset + type location = Abstract_offset.t let pretty = pretty_root diff --git a/src/kernel_services/abstract_interp/abstract_memory.mli b/src/kernel_services/abstract_interp/abstract_memory.mli index 7a9ed21b0d568cbf05308de00cf430defe1f87d1..3100daa6bbf1ac5faa13b742e5eca5e7d659947a 100644 --- a/src/kernel_services/abstract_interp/abstract_memory.mli +++ b/src/kernel_services/abstract_interp/abstract_memory.mli @@ -87,7 +87,7 @@ type strength = Strong | Weak | Reinforce (* update strength *) module TypedMemory (Config : Config) (Value : Value) : sig - type location = Abstract_offset.typed_offset + type location = Abstract_offset.t type value = Value.t type t diff --git a/src/kernel_services/abstract_interp/abstract_offset.ml b/src/kernel_services/abstract_interp/abstract_offset.ml index 4324506eb45abdc043f5983034c59a12f52618d3..25eacbf4e4ab8fbf3ca3c4f177b7c88e302087ce 100644 --- a/src/kernel_services/abstract_interp/abstract_offset.ml +++ b/src/kernel_services/abstract_interp/abstract_offset.ml @@ -38,292 +38,245 @@ struct | `Value t -> `Value (f t) let (let+) = (>>-:) - let (let*) = (>>-) -end - -open Top - -module type T = -sig - type t + let (and+) = zip +let (let*) = (>>-) - val pretty : Format.formatter -> t -> unit - val append : t -> t -> t - val join : t -> t -> t - val of_cil_offset : (Cil_types.exp -> Int_val.t) -> Cil_types.typ -> Cil_types.offset -> t - val of_ival : base_typ:Cil_types.typ -> typ:Cil_types.typ -> Ival.t -> t - val of_term_offset : Cil_types.typ -> Cil_types.term_offset -> t - val is_singleton : t -> bool - val references : t -> Cil_types.varinfo list +let of_option = function + | None -> `Top + | Some x -> `Value x end -type typed_offset = - | NoOffset of Cil_types.typ - | Index of Cil_types.exp option * Int_val.t * Cil_types.typ * typed_offset - | Field of Cil_types.fieldinfo * typed_offset - - -module TypedOffset = -struct - type t = typed_offset +type 'a or_top = [`Value of 'a | `Top] - let rec pretty fmt = function - | NoOffset _t -> () - | Field (fi, s) -> Format.fprintf fmt ".%s%a" fi.fname pretty s - | Index (None, i, _t, s) -> - Format.fprintf fmt "[%a]%a" - Int_val.pretty i - pretty s - | Index (Some e, i, _t, s) -> - Format.fprintf fmt "[%a∈%a]%a" - Cil_printer.pp_exp e - Int_val.pretty i - pretty s - - let rec append o1 o2 = - match o1 with - | NoOffset _t -> o2 - | Field (fi, s) -> Field (fi, append s o2) - | Index (e, i, t, s) -> Index (e, i, t, append s o2) - - let add_index oracle base exp = - let rec aux = function - | NoOffset _ as o -> - let idx = oracle exp in - if Int_val.is_zero idx - then `Value o - else `Top (* Can't add index if not an array *) - | Field (fi, s) -> - let+ s = aux s in - Field (fi, s) - | Index (e, i, t, (NoOffset _ as s)) -> - let idx' = Int_val.add i (oracle exp) in - let loc = Cil_datatype.Location.unknown in - let e = match e with (* If i is singleton, we can use this as the index expression *) - | None when Int_val.is_singleton i -> - let loc = Cil_datatype.Location.unknown in - Some (Cil.kinteger64 ~loc (Int_val.project_int i)) - | e -> e - in - let e' = Option.map (Fun.flip (Cil.mkBinOp ~loc Cil_types.PlusA) exp) e in - (* TODO: is idx inside bounds ? *) - `Value (Index (e', idx', t, s)) - | Index (e, i, t, s) -> - let+ s = aux s in - Index (e, i, t, s) - in - aux base +open Top - let rec join o1 o2 = - match o1, o2 with - | NoOffset t, NoOffset t' - when Bit_utils.type_compatible t t' -> - NoOffset t - | Field (fi, s1), Field (fi', s2) - when Cil_datatype.Fieldinfo.equal fi fi' -> - Field (fi, join s1 s2) - | Index (e1, i1, t, s1), Index (e2, i2, t', s2) - when Bit_utils.type_compatible t t' -> - let e = match e1, e2 with - | Some e1, Some e2 when Cil_datatype.ExpStructEq.equal e1 e2 -> - Some e1 (* keep expression only when equivalent from both offsets *) - | _ -> None +type t = + | NoOffset of Cil_types.typ + | Index of Cil_types.exp option * Int_val.t * Cil_types.typ * t + | Field of Cil_types.fieldinfo * t + +let rec pretty fmt = function + | NoOffset _t -> () + | Field (fi, s) -> Format.fprintf fmt ".%s%a" fi.fname pretty s + | Index (None, i, _t, s) -> + Format.fprintf fmt "[%a]%a" + Int_val.pretty i + pretty s + | Index (Some e, i, _t, s) -> + Format.fprintf fmt "[%a∈%a]%a" + Cil_printer.pp_exp e + Int_val.pretty i + pretty s + +let rec append o1 o2 = + match o1 with + | NoOffset _t -> o2 + | Field (fi, s) -> Field (fi, append s o2) + | Index (e, i, t, s) -> Index (e, i, t, append s o2) + +let add_index oracle base exp = + let rec aux = function + | NoOffset _ as o -> + let idx = oracle exp in + if Int_val.is_zero idx + then `Value o + else `Top (* Can't add index if not an array *) + | Field (fi, sub) -> + let+ sub' = aux sub in + Field (fi, sub') + | Index (e, i, t, (NoOffset _ as sub)) -> + let idx' = Int_val.add i (oracle exp) in + let loc = Cil_datatype.Location.unknown in + let e = match e with (* If i is singleton, we can use this as the index expression *) + | None when Int_val.is_singleton i -> + let loc = Cil_datatype.Location.unknown in + Some (Cil.kinteger64 ~loc (Int_val.project_int i)) + | e -> e in - Index (e, Int_val.join i1 i2, t, join s1 s2) - | _ -> raise Abstract_interp.Error_Top - - let array_bounds array_size = - (* TODO: handle undefined sizes and not const foldable sizes *) - match array_size with + let e' = Option.map (Fun.flip (Cil.mkBinOp ~loc Cil_types.PlusA) exp) e in + (* TODO: is idx inside bounds ? *) + `Value (Index (e', idx', t, sub)) + | Index (e, i, t, sub) -> + let+ sub' = aux sub in + Index (e, i, t, sub') + in + aux base + +let rec join o1 o2 = + match o1, o2 with + | NoOffset t, NoOffset t' + when Bit_utils.type_compatible t t' -> + `Value (NoOffset t) + | Field (fi, sub1), Field (fi', sub2) + when Cil_datatype.Fieldinfo.equal fi fi' -> + let+ sub' = join sub1 sub2 in + Field (fi, sub') + | Index (e1, i1, t, sub1), Index (e2, i2, t', sub2) + when Bit_utils.type_compatible t t' -> + let e = match e1, e2 with + | Some e1, Some e2 when Cil_datatype.ExpStructEq.equal e1 e2 -> + Some e1 (* keep expression only when equivalent from both offsets *) + | _ -> None + in + let+ sub' = join sub1 sub2 in + Index (e, Int_val.join i1 i2, t, sub') + | _ -> `Top + +let array_bounds array_size = + (* TODO: handle undefined sizes and not const foldable sizes *) + match array_size with + | None -> None + | Some size_exp -> + match Cil.constFoldToInt size_exp with | None -> None - | Some size_exp -> - match Cil.constFoldToInt size_exp with - | None -> None - | Some size when Integer.(gt size zero) -> Some Integer.(zero, pred size) - | Some _ -> None - - let array_range array_size = - Option.map - (fun (l,u) -> Int_val.inject_range (Some l) (Some u)) - (array_bounds array_size) - - let assert_valid_index idx size = - match array_range size with - | Some range when Int_val.is_included idx range -> () - | _ -> raise Abstract_interp.Error_Top - - let rec of_cil_offset oracle base_typ = function - | Cil_types.NoOffset -> NoOffset base_typ - | Field (fi, sub) -> - if Cil.typeHasQualifier "volatile" fi.ftype then - raise Abstract_interp.Error_Top - else - Field (fi, of_cil_offset oracle fi.ftype sub) - | Index (exp, sub) -> - match Cil.unrollType base_typ with - | TArray (elem_typ, array_size, _) -> - let idx = oracle exp in - assert_valid_index idx array_size; - Index (Some exp, idx, elem_typ, of_cil_offset oracle elem_typ sub) - | _ -> assert false - - let rec of_int_val ~base_typ ~typ ival = - if Int_val.is_zero ival && Bit_utils.type_compatible base_typ typ then - NoOffset typ + | Some size when Integer.(gt size zero) -> Some Integer.(zero, pred size) + | Some _ -> None + +let array_range array_size = + Option.map + (fun (l,u) -> Int_val.inject_range (Some l) (Some u)) + (array_bounds array_size) + +let assert_valid_index idx size = + match array_range size with + | Some range when Int_val.is_included idx range -> `Value () + | _ -> `Top + +let of_var_address vi = + NoOffset vi.Cil_types.vtype + +let rec of_cil_offset oracle base_typ = function + | Cil_types.NoOffset -> `Value (NoOffset base_typ) + | Field (fi, sub) -> + if Cil.typeHasQualifier "volatile" fi.ftype then + `Top else - match Cil.unrollType base_typ with - | TArray (elem_typ, array_size, _) -> - let range, rem = - try - let elem_size = Integer.of_int (Cil.bitsSizeOf elem_typ) in - if Integer.is_zero elem_size then (* array of elements of size 0 *) - if Int_val.is_zero ival then (* the whole range is valid *) - let range = array_range array_size in - Extlib.the ~exn:Abstract_interp.Error_Top range, ival - else (* Non-zero offset cannot represent anything here *) - raise Abstract_interp.Error_Top - else - Int_val.scale_div ~pos:true elem_size ival, - Int_val.scale_rem ~pos:true elem_size ival - with Cil.SizeOfError (_,_) -> - (* Cil.bitsSizeOf can raise an exception when elements are - themselves array of execution-time size *) - if Int_val.is_zero ival then - ival, ival - else - raise Abstract_interp.Error_Top - in - assert_valid_index range array_size; - let sub = of_int_val ~base_typ:elem_typ ~typ rem in - Index (None, range, elem_typ, sub) - - | TComp (ci, _) -> - if not ci.cstruct then - (* Ignore unions for now *) - raise Abstract_interp.Error_Top - else - let rec find_field = function - | [] -> raise Abstract_interp.Error_Top - | fi :: q -> - let offset, width = Cil.fieldBitsOffset fi in - let l = Integer.(of_int offset) in - let u = Integer.(pred (add l (of_int width))) in - let matches = - if width = 0 then - Int_val.(equal ival (inject_singleton l)) - else - let range = Int_val.inject_range (Some l) (Some u) in - Int_val.is_included ival range - in - if matches then - if Cil.typeHasQualifier "volatile" fi.ftype then - raise Abstract_interp.Error_Top - else - let sub_ival = Int_val.add_singleton (Integer.neg l) ival in - Field (fi, of_int_val ~base_typ:fi.ftype ~typ sub_ival) - else - find_field q - in - find_field (Option.value ~default:[] ci.cfields) - - | _ -> raise Abstract_interp.Error_Top - - let of_ival ~base_typ ~typ ival = - match Ival.project_int_val ival with - | Some ival -> of_int_val ~base_typ ~typ ival - | None -> raise Abstract_interp.Error_Top (* should not happen *) - - let index_of_term array_size t = (* Exact constant ranges *) - match t.Cil_types.term_node with - | TConst (Integer (v, _)) -> Int_val.inject_singleton v - | Trange (l,u) -> - let eval bound = function - | None -> Extlib.the ~exn:Abstract_interp.Error_Top bound - | Some { Cil_types.term_node=TConst (Integer (v, _)) } -> v - | Some _ -> raise Abstract_interp.Error_Top + let+ sub' = of_cil_offset oracle fi.ftype sub in + Field (fi, sub') + | Index (exp, sub) -> + match Cil.unrollType base_typ with + | TArray (elem_typ, array_size, _) -> + let idx = oracle exp in + let+ () = assert_valid_index idx array_size + and+ sub' = of_cil_offset oracle elem_typ sub in + Index (Some exp, idx, elem_typ, sub') + | _ -> assert false + +let rec of_int_val ~base_typ ~typ ival = + if Int_val.is_zero ival && Bit_utils.type_compatible base_typ typ then + `Value (NoOffset typ) + else + match Cil.unrollType base_typ with + | TArray (elem_typ, array_size, _) -> + let* range, rem = + try + let elem_size = Integer.of_int (Cil.bitsSizeOf elem_typ) in + if Integer.is_zero elem_size then (* array of elements of size 0 *) + if Int_val.is_zero ival then (* the whole range is valid *) + let+ range = Top.of_option (array_range array_size) in + range, ival + else (* Non-zero offset cannot represent anything here *) + `Top + else + let range = Int_val.scale_div ~pos:true elem_size ival + and rem = Int_val.scale_rem ~pos:true elem_size ival in + `Value (range, rem) + with Cil.SizeOfError (_,_) -> + (* Cil.bitsSizeOf can raise an exception when elements are + themselves array of execution-time size *) + if Int_val.is_zero ival then + `Value (ival, ival) + else + `Top in - let bounds = array_bounds array_size in - let lb = Option.map fst bounds and ub = Option.map snd bounds in - let l' = eval lb l and u' = eval ub u in - Int_val.inject_range (Some l') (Some u') - | _ -> raise Abstract_interp.Error_Top - - let rec of_term_offset base_typ = function - | Cil_types.TNoOffset -> NoOffset base_typ - | TField (fi, sub) -> - if Cil.typeHasQualifier "volatile" fi.ftype then - raise Abstract_interp.Error_Top + let+ () = assert_valid_index range array_size + and+ sub' = of_int_val ~base_typ:elem_typ ~typ rem in + Index (None, range, elem_typ, sub') + + | TComp (ci, _) -> + if not ci.cstruct then + (* Ignore unions for now *) + `Top else - Field (fi, of_term_offset fi.ftype sub) - | TIndex (index, sub) -> - begin match Cil.unrollType base_typ with - | TArray (elem_typ, array_size, _) -> - let idx = index_of_term array_size index in - assert_valid_index idx array_size; - Index (None, idx, elem_typ, of_term_offset elem_typ sub) - | _ -> assert false - end - | _ -> raise Abstract_interp.Error_Top - - let rec is_singleton = function - | NoOffset _ -> true - | Field (_fi, sub) -> is_singleton sub - | Index (e, ival, _elem_typ, sub) -> - (Option.is_some e || Int_val.is_singleton ival) && is_singleton sub - - let references = - let rec aux acc = function - | NoOffset _ -> acc - | Field (_, sub) | Index (None, _, _, sub) -> aux acc sub - | Index (Some e, _, _, sub) -> - let r = Cil.extract_varinfos_from_exp e in - let acc = (Cil_datatype.Varinfo.Set.to_seq r |> List.of_seq) @ acc in - aux acc sub + let rec find_field = function + | [] -> `Top + | fi :: q -> + let offset, width = Cil.fieldBitsOffset fi in + let l = Integer.(of_int offset) in + let u = Integer.(pred (add l (of_int width))) in + let matches = + if width = 0 then + Int_val.(equal ival (inject_singleton l)) + else + let range = Int_val.inject_range (Some l) (Some u) in + Int_val.is_included ival range + in + if matches then + if Cil.typeHasQualifier "volatile" fi.ftype then + `Top + else + let sub_ival = Int_val.add_singleton (Integer.neg l) ival in + let+ sub' = of_int_val ~base_typ:fi.ftype ~typ sub_ival in + Field (fi, sub') + else + find_field q + in + find_field (Option.value ~default:[] ci.cfields) + + | _ -> `Top + +let of_ival ~base_typ ~typ ival = + match Ival.project_int_val ival with + | Some ival -> of_int_val ~base_typ ~typ ival + | None -> `Top (* should not happen *) + +let index_of_term array_size t = (* Exact constant ranges *) + match t.Cil_types.term_node with + | TConst (Integer (v, _)) -> `Value (Int_val.inject_singleton v) + | Trange (l,u) -> + let eval bound = function + | None -> Top.of_option bound + | Some { Cil_types.term_node=TConst (Integer (v, _)) } -> `Value v + | Some _ -> `Top in - aux [] -end - -module TypedOffsetOrTop = -struct - type t = [ `Value of typed_offset | `Top ] - - let pretty fmt = function - | `Top -> Format.pp_print_string fmt "T" - | `Value o -> TypedOffset.pretty fmt o - - let append o1 o2 = - match o1, o2 with - | `Top, _ | _, `Top -> `Top - | `Value o1, `Value o2 -> `Value (TypedOffset.append o1 o2) - - let add_index oracle base exp = - let* base = base in - TypedOffset.add_index oracle base exp - - let join o1 o2 = - match o1, o2 with - | `Top, _ | _, `Top -> `Top - | `Value o1, `Value o2 -> - try `Value (TypedOffset.join o1 o2) - with Abstract_interp.Error_Top -> `Top - - let of_cil_offset oracle base_typ offset = - try `Value (TypedOffset.of_cil_offset oracle base_typ offset) - with Abstract_interp.Error_Top -> `Top - - let of_ival ~base_typ ~typ ival = - try `Value (TypedOffset.of_ival ~base_typ ~typ ival) - with Abstract_interp.Error_Top -> `Top - - let of_term_offset base_typ toffset = - try `Value (TypedOffset.of_term_offset base_typ toffset) - with Abstract_interp.Error_Top -> `Top - - let is_singleton = function - | `Top -> false - | `Value o -> TypedOffset.is_singleton o - - let references = function - | `Top -> [] - | `Value o -> TypedOffset.references o -end + let bounds = array_bounds array_size in + let lb = Option.map fst bounds and ub = Option.map snd bounds in + let+ l' = eval lb l and+ u' = eval ub u in + Int_val.inject_range (Some l') (Some u') + | _ -> `Top + +let rec of_term_offset base_typ = function + | Cil_types.TNoOffset -> `Value (NoOffset base_typ) + | TField (fi, sub) -> + if Cil.typeHasQualifier "volatile" fi.ftype then + `Top + else + let+ sub' = of_term_offset fi.ftype sub in + Field (fi, sub') + | TIndex (index, sub) -> + begin match Cil.unrollType base_typ with + | TArray (elem_typ, array_size, _) -> + let* idx = index_of_term array_size index in + let+ () = assert_valid_index idx array_size + and+ sub' = of_term_offset elem_typ sub in + Index (None, idx, elem_typ, sub') + | _ -> assert false + end + | _ -> `Top + +let rec is_singleton = function + | NoOffset _ -> true + | Field (_fi, sub) -> is_singleton sub + | Index (e, ival, _elem_typ, sub) -> + (Option.is_some e || Int_val.is_singleton ival) && is_singleton sub + +let references = + let rec aux acc = function + | NoOffset _ -> acc + | Field (_, sub) | Index (None, _, _, sub) -> aux acc sub + | Index (Some e, _, _, sub) -> + let r = Cil.extract_varinfos_from_exp e in + let acc = (Cil_datatype.Varinfo.Set.to_seq r |> List.of_seq) @ acc in + aux acc sub + in + aux [] diff --git a/src/kernel_services/abstract_interp/abstract_offset.mli b/src/kernel_services/abstract_interp/abstract_offset.mli index 368cce1d4e3f2bbc901e7229c2535c68c0f2cc86..457393b96da61ec366c9323f73e06874b69dcdb6 100644 --- a/src/kernel_services/abstract_interp/abstract_offset.mli +++ b/src/kernel_services/abstract_interp/abstract_offset.mli @@ -20,28 +20,24 @@ (* *) (**************************************************************************) -module type T = -sig - type t +type t = + | NoOffset of Cil_types.typ + | Index of Cil_types.exp option * Int_val.t * Cil_types.typ * t + | Field of Cil_types.fieldinfo * t - val pretty : Format.formatter -> t -> unit - val append : t -> t -> t (* Does not check that the appened offset fits *) - val join : t -> t -> t - val of_cil_offset : (Cil_types.exp -> Int_val.t) -> Cil_types.typ -> Cil_types.offset -> t - val of_ival : base_typ:Cil_types.typ -> typ:Cil_types.typ -> Ival.t -> t - val of_term_offset : Cil_types.typ -> Cil_types.term_offset -> t - val is_singleton : t -> bool - val references : t -> Cil_types.varinfo list (* variables referenced in the offset *) -end +type 'a or_top = [`Value of 'a | `Top] -type typed_offset = - | NoOffset of Cil_types.typ - | Index of Cil_types.exp option * Int_val.t * Cil_types.typ * typed_offset - | Field of Cil_types.fieldinfo * typed_offset +val pretty : Format.formatter -> t -> unit + +val of_var_address : Cil_types.varinfo -> t +val of_cil_offset : (Cil_types.exp -> Int_val.t) -> + Cil_types.typ -> Cil_types.offset -> t or_top +val of_ival : base_typ:Cil_types.typ -> typ:Cil_types.typ -> Ival.t -> t or_top +val of_term_offset : Cil_types.typ -> Cil_types.term_offset -> t or_top + +val is_singleton : t -> bool +val references : t -> Cil_types.varinfo list (* variables referenced in the offset *) -module TypedOffset : T with type t = typed_offset -module TypedOffsetOrTop : -sig - include T with type t = [ `Value of typed_offset | `Top ] - val add_index : (Cil_types.exp -> Int_val.t) -> t -> Cil_types.exp -> t -end +val append : t -> t -> t (* Does not check that the appened offset fits *) +val join : t -> t -> t or_top +val add_index : (Cil_types.exp -> Int_val.t) -> t -> Cil_types.exp -> t or_top diff --git a/src/plugins/value/domains/multidim_domain.ml b/src/plugins/value/domains/multidim_domain.ml index 411bc31ff5184bef71af4e99204372764ac9c795..75473ca8fc09bb3fde3946ec72fa96e4ce6705ea 100644 --- a/src/plugins/value/domains/multidim_domain.ml +++ b/src/plugins/value/domains/multidim_domain.ml @@ -25,6 +25,32 @@ open Eval let dkey = Self.register_category "d-multidim" +module Top = +struct + [@@@warning "-32"] + + let zip x y = + match x, y with + | `Top, _ | _, `Top -> `Top + | `Value x, `Value y -> `Value (x,y) + + let (>>-) t f = match t with + | `Top -> `Top + | `Value t -> f t + + let (>>-:) t f = match t with + | `Top -> `Top + | `Value t -> `Value (f t) + + let (let+) = (>>-:) + let (and+) = zip +let (let*) = (>>-) + +let of_option = function + | None -> `Top + | Some x -> `Value x +end + let map_to_singleton map = let aux base offset = function | None -> Some (base, offset) @@ -121,12 +147,11 @@ let find_builtin = module Location = struct - open Abstract_offset - - module Offset = TypedOffsetOrTop + module Offset = Abstract_offset module Map = Base.Base.Map + open Top - type offset = Offset.t + type offset = Offset.t or_top type base = Base.t type t = offset Map.t @@ -145,19 +170,22 @@ struct match map_to_singleton map with | None -> false | Some (b,o) -> - not (Base.is_weak b) && Offset.is_singleton o + match o with + | `Top -> false + | `Value o -> not (Base.is_weak b) && Offset.is_singleton o - let references map = + let references (map : t) = let module Set = Cil_datatype.Varinfo.Set in - let add_refs _b o = - Set.union (Set.of_list (Offset.references o)) + let add_refs _b o acc = + match o with + | `Top -> acc + | `Value o -> Set.union (Set.of_list (Offset.references o)) acc in Map.fold add_refs map Set.empty |> Set.to_seq |> List.of_seq let of_var (vi : Cil_types.varinfo) : t = - Map.singleton (Base.of_varinfo vi) (`Value (NoOffset vi.vtype)) + Map.singleton (Base.of_varinfo vi) (`Value (Offset.of_var_address vi)) - (* Raises Abstract_domain.{Error_top,Error_bottom} *) let of_lval oracle ((host,offset) as lval : Cil_types.lval) : t = let oracle' = convert_oracle oracle in let base_typ = Cil.typeOfLhost host in @@ -176,16 +204,18 @@ struct | _ -> exp, None in let add base ival map = - let offset' : Offset.t = + let offset' : Offset.t or_top = match Base.typeof base with | None -> `Top | Some base_typ -> let typ = Cil.typeOf_pointed (Cil.typeOf exp) in - let base_offset = Offset.of_ival ~base_typ ~typ ival in - let base_offset = match index with - | None -> base_offset - | Some exp -> Offset.add_index oracle' base_offset exp + let* base_offset = Offset.of_ival ~base_typ ~typ ival in + let* base_offset = match index with + | None -> `Value (base_offset) + | Some exp -> + Offset.add_index oracle' base_offset exp in + let+ offset = offset in Offset.append base_offset offset in Map.add base offset' map @@ -213,7 +243,7 @@ struct let add_base base map = (* Null base doesn't have a type ; use void instead *) let typ = Option.value ~default:Cil.voidType (Base.typeof base) in - Map.add base (`Value (NoOffset typ)) map + Map.add base (`Value (Offset.NoOffset typ)) map in Locations.Location_Bits.(fold_bases add_base loc'.loc empty) end