diff --git a/src/plugins/alias/API.ml b/src/plugins/alias/API.ml index 5835322fd107ecba1b6b77f0d2b04c02247bd19e..84509b9cd278681df533efcc7fe046c4ee086a6f 100644 --- a/src/plugins/alias/API.ml +++ b/src/plugins/alias/API.ml @@ -22,12 +22,10 @@ open Cil_types -open Simplified - (** Points-to graphs datastructure. *) module G = Abstract_state.G -module LSet = Simplified_lset +module LSet = Abstract_state.LSet module Abstract_state = Abstract_state @@ -37,51 +35,84 @@ let check_computed () = Options.abort "Static analysis must be called before any function of the API can be called" -let fold_aliases_stmt (f_fold : 'a -> lval -> 'a) (acc: 'a) (kf: kernel_function) (s:stmt) (lv: lval) : 'a = +let lset + (get_set : Abstract_state.t -> LSet.t) + (kf : kernel_function) (s : stmt) = check_computed (); match Analysis.get_state_before_stmt kf s with - None -> acc - | Some state -> - let set_aliases = Abstract_state.find_all_aliases lv state in - LSet.fold_lval (fun e a -> f_fold a e) set_aliases acc + | None -> LSet.empty + | Some state -> get_set state -let fold_new_aliases_stmt (f_fold: 'a -> lval -> 'a) (acc: 'a) (kf:kernel_function) (s:stmt) (lv:lval) : 'a = - check_computed (); - match Analysis.get_state_before_stmt kf s with - None -> acc - | Some state -> +let points_to_set kf s lv = lset (Abstract_state.points_to_set lv) kf s + +let new_points_to_set_stmt kf s lv = + let get_set state = let new_state = Analysis.do_stmt state s in - let set_aliases = Abstract_state.find_all_aliases lv new_state in - LSet.fold_lval (fun e a -> f_fold a e) set_aliases acc + Abstract_state.points_to_set lv new_state + in + lset get_set kf s -let fold_aliases_kf (f_fold: 'a -> lval -> 'a) (acc: 'a) (kf:kernel_function) (lv:lval) : 'a = +let aliases_stmt kf s lv = + lset (Abstract_state.find_all_aliases lv) kf s + +let new_aliases_stmt kf s lv = + let get_set state = + let new_state = Analysis.do_stmt state s in + Abstract_state.find_all_aliases lv new_state + in + lset get_set kf s + +let points_to_set_kf (kf : kernel_function) (lv : lval) = check_computed (); if Kernel_function.has_definition kf then let s = Kernel_function.find_return kf in - fold_new_aliases_stmt f_fold acc kf s lv + new_points_to_set_stmt kf s lv else - Options.abort "fold_aliases_kf: function %a has no definition" Kernel_function.pretty kf + Options.abort "points_to_set_kf: function %a has no definition" Kernel_function.pretty kf -let fold_fundec_stmts (f_fold: 'a -> stmt -> lval -> 'a) (acc: 'a) (kf:kernel_function) (lv:lval) : 'a = +let aliases_kf (kf : kernel_function) (lv : lval) = check_computed (); if Kernel_function.has_definition kf then - let f_dec = Kernel_function.get_definition kf in - let list_stmt = f_dec.sallstmts in - List.fold_left - (fun acc s -> - fold_new_aliases_stmt - (fun a lv -> f_fold a s lv) - acc - kf - s - lv - ) - acc - list_stmt + let s = Kernel_function.find_return kf in + new_aliases_stmt kf s lv else - Options.abort "fold_fundec_stmts: function %a has no definition" Kernel_function.pretty kf + Options.abort "aliases_kf: function %a has no definition" Kernel_function.pretty kf + +let fundec_stmts (kf : kernel_function) (lv : lval) = + check_computed (); + if Kernel_function.has_definition kf + then + List.map + (fun s -> s, new_aliases_stmt kf s lv) + (Kernel_function.get_definition kf).sallstmts + else + Options.abort "fundec_stmts: function %a has no definition" Kernel_function.pretty kf + + +let fold_points_to_set f_fold acc kf s lv = + LSet.fold (fun e a -> f_fold a e) (points_to_set kf s lv) acc + +let fold_aliases_stmt f_fold acc kf s lv = + LSet.fold (fun e a -> f_fold a e) (aliases_stmt kf s lv) acc + +let fold_new_aliases_stmt f_fold acc kf s lv = + LSet.fold (fun e a -> f_fold a e) (new_aliases_stmt kf s lv) acc + +let fold_points_to_set_kf (f_fold: 'a -> lval -> 'a) (acc: 'a) (kf:kernel_function) (lv:lval) : 'a = + LSet.fold (fun e a -> f_fold a e) (points_to_set_kf kf lv) acc + +let fold_aliases_kf (f_fold : 'a -> lval -> 'a) (acc : 'a) (kf : kernel_function) (lv : lval) : 'a = + LSet.fold (fun e a -> f_fold a e) (aliases_kf kf lv) acc + +let fold_fundec_stmts (f_fold: 'a -> stmt -> lval -> 'a) (acc: 'a) (kf:kernel_function) (lv:lval) : 'a = + List.fold_left + (fun acc (s, set) -> + LSet.fold (fun lv a -> f_fold a s lv) set acc + ) + acc + (fundec_stmts kf lv) let are_aliased (kf: kernel_function) (s:stmt) (lv1: lval) (lv2:lval) : bool = check_computed (); @@ -89,16 +120,16 @@ let are_aliased (kf: kernel_function) (s:stmt) (lv1: lval) (lv2:lval) : bool = None -> false | Some state -> let setv1 = Abstract_state.find_all_aliases lv1 state in - LSet.mem (BLval lv2) setv1 + LSet.mem lv2 setv1 -let fold_vertex (f_fold : 'a -> G.V.t -> lval -> 'a) (acc: 'a) (kf: kernel_function) (s:stmt) (lv: lval) : 'a = +let fold_vertex (f_fold : 'a -> G.V.t -> lval -> 'a) (acc: 'a) (kf: kernel_function) (s:stmt) (lv: lval) : 'a = check_computed (); match Analysis.get_state_before_stmt kf s with None -> acc | Some state -> let v : G.V.t = Abstract_state.find_vertex lv state in let set_aliases = Abstract_state.find_aliases lv state in - LSet.fold_lval (fun lv a-> f_fold a v lv) set_aliases acc + LSet.fold (fun lv a-> f_fold a v lv) set_aliases acc let fold_vertex_closure (f_fold : 'a -> G.V.t -> lval -> 'a) (acc: 'a) (kf: kernel_function) (s:stmt) (lv: lval) : 'a = check_computed (); @@ -107,7 +138,7 @@ let fold_vertex_closure (f_fold : 'a -> G.V.t -> lval -> 'a) (acc: 'a) (kf: ker | Some state -> let list_closure : (G.V.t * LSet.t) list = Abstract_state.find_transitive_closure lv state in List.fold_left - (fun acc (i,s) -> LSet.fold_lval (fun lv a -> f_fold a i lv) s acc) + (fun acc (i,s) -> LSet.fold (fun lv a -> f_fold a i lv) s acc) acc list_closure @@ -119,8 +150,4 @@ let call_function a f res args = None -> None | Some su -> Some(Abstract_state.call a res args su) - -let simplify_lval (lv:lval) : lval = - match Simplified.Simplified_lval.from_lval lv with - BLval lv -> lv - | _ -> Options.fatal "This should not happen" +let simplify_lval = Simplified.Lval.simplify diff --git a/src/plugins/alias/API.mli b/src/plugins/alias/API.mli index 27061c9d911f1d14139fcd263b248c9f444d3e53..2ea9b4efc629d7612596bf442c96376370ba6b4b 100644 --- a/src/plugins/alias/API.mli +++ b/src/plugins/alias/API.mli @@ -27,8 +27,34 @@ open Cil_types (** Points-to graphs datastructure. *) module G: Graph.Sig.G +(** Set of [lval]s. Differs from Cil_datatype.Lval.Set in that is uses a + different comparison function ([Cil_datatype.LvalStructEq.compare]). *) +module LSet : sig + include Set.S with type elt = lval + + val pretty: Format.formatter -> t -> unit +end + (** NB : do the analysis BEFORE using any of those functions *) + +(** points-to set of lval [lv] at the end of function [kf]. *) +val points_to_set_kf : kernel_function -> lval -> LSet.t + +(** aliases of lval [lv] at the end of function [kf]. *) +val aliases_kf : kernel_function -> lval -> LSet.t + +(** list of pairs [s, e] where [e] is the set of lval aliased to [v] after + statement [s] in function [kf]. *) +val fundec_stmts : kernel_function -> lval -> (stmt * LSet.t) list + + +(** [fold_points_to_set f acc kf s lv] folds [f acc] over all the lvals in the + points-to set of the given lval [lv] right before stmt [s] in function + [kf]. *) +val fold_points_to_set: + ('a -> lval -> 'a) -> 'a -> kernel_function -> stmt -> lval -> 'a + (** [fold_aliases_stmt f acc kf s lv] folds [f acc] over all the aliases of the given lval [lv] right before stmt [s] in function [kf]. *) val fold_aliases_stmt: @@ -39,6 +65,11 @@ val fold_aliases_stmt: val fold_new_aliases_stmt: ('a -> lval -> 'a) -> 'a -> kernel_function -> stmt -> lval -> 'a +(** [fold_points_to_set_kf f acc kf lv] folds [f acc] over the points-to set of lval + [lv] at the end of function [kf]. *) +val fold_points_to_set_kf : + ('a -> lval -> 'a) -> 'a -> kernel_function -> lval -> 'a + (** [fold_aliases_kf f acc kf lv] folds [f acc] over all the aliases of lval [lv] at the end of function [kf]. *) val fold_aliases_kf: diff --git a/src/plugins/alias/README.md b/src/plugins/alias/README.md index d910283cac9ea0d23b89efdbe32e54c37e1ffdbd..7dc75b04fa8aa09845800030779fa2cbd8486d57 100644 --- a/src/plugins/alias/README.md +++ b/src/plugins/alias/README.md @@ -1,14 +1,17 @@ # May-Alias Analysis plugin -Alias is a Frama-C plugin that implements a may-alias analysis, i.e. an -over-approximation of the possible aliases between variables (and, more -generally, memory regions) of the program. +Alias is a Frama-C plugin that implements: +- a points-to analysis, i.e. an over-approximation of the possible values a + pointer may point to at run-time. +- a may-alias analysis, i.e. an over-approximation of the possible aliases + between pointer variables (and, more generally, memory regions) of the + program. -Two pointers are called aliases of each other if they -point at runtime to the same memory location. In that case changing the value -of one pointer also changes the value of the other pointer and vice versa. +Two pointers are called aliases of each other if they point at runtime to the +same memory location. In that case changing the value of one pointer also +changes the value of the other pointer and vice versa. -The algorithm is a variant of « Steensgaard's algorithm ». +The plugin implements a variant of « Steensgaard's algorithm ». ## Usage @@ -45,12 +48,12 @@ Therefore the analysis is efficient, whereas the results are not very precise. program, whichever the execution path is. ### Imprecisely-supported constructs -- Non-complex instruction goto -- Homogeneous casts -- Recursive datatype, e.g., multiple levels of pointer dereferencing -- Pointer arithmetic, and array and structure accesses -- Variable-length arrays -- Volatile attributes +- non-complex instruction goto +- homogeneous casts +- recursive datatype, e.g., multiple levels of pointer dereferencing +- pointer arithmetic, and array and structure accesses +- variable-length arrays +- volatile attributes ## Building and Installation diff --git a/src/plugins/alias/abstract_state.ml b/src/plugins/alias/abstract_state.ml index 98e30f62157409b7473277af7d0c98cadfd7a532..b1cc43122d90c913a6dcd876a1b4c21f71f1feb6 100644 --- a/src/plugins/alias/abstract_state.ml +++ b/src/plugins/alias/abstract_state.ml @@ -31,9 +31,39 @@ open Simplified module VSet = Datatype.Int.Set module VMap = Datatype.Int.Map -module Lval = Simplified.Simplified_lval -module LSet = Simplified.Simplified_lset -module LMap = Simplified.Simplified_lmap +module Lval = Simplified.Lval + +module LSet = struct + include Set.Make (Lval) + + let pretty fmt s = + Format.fprintf fmt "{@["; + let is_first = ref true in + iter (fun e -> + if !is_first + then is_first := false + else Format.fprintf fmt ",@ "; + Format.fprintf fmt "%a" Lval.pretty e + ) + s; + Format.fprintf fmt "@]}" +end + +module LMap = struct + include Map.Make (Lval) + + let pretty f fmt m = + let is_first = ref true in + Format.fprintf fmt "{@[<hov 2>"; + iter (fun k v -> + if not !is_first + then Format.fprintf fmt ",@," + else is_first := false; + Format.fprintf fmt " %a -> %a" Lval.pretty k f v + ) + m; + Format.fprintf fmt " @]}" +end module G = Persistent.Digraph.ConcreteBidirectional(Datatype.Int) @@ -48,64 +78,33 @@ struct let empty : t = LMap.empty - let mem (lv:Lval.t) (m:t) = - let lv, off = Lval.removeOffsetLval lv in + let mem (lv : lval) (m:t) = + let lv, off = Cil.removeOffsetLval lv in try OMap.mem off (LMap.find lv m) with Not_found -> false - let find (lv:Lval.t) (m:t) : V.t = - let lv, off = Lval.removeOffsetLval lv in + let find (lv : lval) (m:t) : V.t = + let lv, off = Cil.removeOffsetLval lv in OMap.find off (LMap.find lv m) - let add (lv:Lval.t) (v:V.t) (m:t) :t = - let lv, off = Lval.removeOffsetLval lv in + let add (lv : lval) (v:V.t) (m:t) :t = + let lv, off = Cil.removeOffsetLval lv in let mo = try LMap.find lv m with Not_found -> OMap.empty in LMap.add lv (OMap.add off v mo) m - let remove (lv:Lval.t) (m:t) :t = - let lv, off = Lval.removeOffsetLval lv in - let mo = try LMap.find lv m with Not_found -> OMap.empty in - let res = OMap.remove off mo in - if OMap.is_empty res - then - LMap.remove lv m - else - LMap.add lv res m - - let iter (f_iter: Lval.t -> V.t -> unit) (m:t) : unit = - LMap.iter - (fun lv mo -> - OMap.iter - (fun o v -> - let lv = Lval.addOffsetLval o lv in - f_iter lv v - ) - mo - ) - m - - let map (f_map: V.t -> V.t ) (m:t) : 'a = - LMap.map - (fun mo -> - OMap.map - f_map - mo - ) - m + let iter f = LMap.iter @@ fun lv -> OMap.iter @@ fun o -> f @@ Cil.addOffsetLval o lv + + let map f = LMap.map @@ OMap.map f - let pretty fmt (m:t) = + let pretty fmt = let is_first = ref true in - LMap.iter - (fun lv mo -> - OMap.iter - (fun o v -> let lv = Lval.addOffsetLval o lv in - if !is_first then is_first := false else Format.fprintf fmt "@;<3>"; - Format.fprintf fmt "@ @[%a:%d@]" Lval.pretty lv v) - mo - ) - m + LMap.iter (fun lv -> + OMap.iter + (fun o v -> let lv = Cil.addOffsetLval o lv in + if !is_first then is_first := false else Format.fprintf fmt "@;<3>"; + Format.fprintf fmt "@ @[%a:%d@]" Lval.pretty lv v)) (* left-biased *) let union = LMap.union @@ fun _ l r -> Some (OMap.union (fun _ l _r -> Some l) l r) @@ -123,7 +122,7 @@ struct in LMap.merge @@ fun _ -> intersect_lmap - let to_seq m = LMap.fold (fun lv omap s -> OMap.fold (fun o v s -> Seq.cons (lv,o,v) s) omap s) m Seq.empty + let to_seq m = LMap.fold (fun lv omap -> OMap.fold (fun o v s -> Seq.cons (lv,o,v) s) omap) m Seq.empty (* specialized functions *) let rec is_sub_offset o1 o2 = @@ -134,13 +133,13 @@ struct | _ -> false (* finds all the lval lv1 apearing in [m] such as there exists an offset o1 and lv1 + o1 = lv *) - let find_upper_offsets (lv:Lval.t) (m:t) : V.t LMap.t = - let lv, off = Lval.removeOffsetLval lv in + let find_upper_offsets (lv : lval) (m:t) : V.t LMap.t = + let lv, off = Cil.removeOffsetLval lv in let mo = try LMap.find lv m with Not_found -> OMap.empty in let f_filter o _v = is_sub_offset o off in let mo = OMap.filter f_filter mo in OMap.fold - (fun o v acc -> let lv = Lval.addOffsetLval o lv in LMap.add lv v acc) + (fun o -> let lv = Cil.addOffsetLval o lv in LMap.add lv) mo LMap.empty @@ -148,28 +147,18 @@ end module type S = sig - - (* see .mli for coments *) + (* see abstract_state.mli for coments *) type t - val get_graph: t -> G.t - val get_lval_set : G.V.t -> t -> LSet.t - val pretty : ?debug:bool -> Format.formatter -> t -> unit - val print_dot : string -> t -> unit - val find_vertex : lval -> t -> G.V.t - val find_aliases : lval -> t -> LSet.t - val find_all_aliases : lval -> t -> LSet.t - + val points_to_set : lval -> t -> LSet.t val find_transitive_closure : lval -> t -> (G.V.t * LSet.t) list - val is_included : t -> t -> bool - end type t = { @@ -190,7 +179,7 @@ let find_lset (v:V.t) (x:t) : LSet.t = with Not_found -> LSet.empty let find_aliases (lv:lval) (x:t) = - let lv : Lval.t = Lval.from_lval lv in + let lv = Lval.simplify lv in try let v = LLMap.find lv x.lmap in find_lset v x @@ -216,18 +205,25 @@ let aliases_of_vertex (v:V.t) (x:t) : LSet.t = LSet.empty list_pred +let succ_of_lval (lv:lval) (x:t) : int option = + let lv = Lval.simplify lv in + try begin + let v = LLMap.find lv x.lmap in + match G.succ x.graph v with + | [] -> None + | [succ_v] -> Some succ_v + | _ -> Options.fatal "invariant violated (more than 1 successor)" + end with Not_found -> None + let find_all_aliases (lv:lval) (x:t) : LSet.t = - let lv : Lval.t = Lval.from_lval lv in - try - begin - let v = LLMap.find lv x.lmap in - match G.succ x.graph v with - [] -> find_lset v x - | [succ_v] -> - aliases_of_vertex succ_v x - | _ -> Options.fatal "invariant violated (more than 1 successor)" - end - with Not_found -> LSet.empty + match succ_of_lval lv x with + | None -> LSet.empty + | Some succ_v -> aliases_of_vertex succ_v x + +let points_to_set (lv:lval) (x:t) : LSet.t = + match succ_of_lval lv x with + | None -> LSet.empty + | Some succ_v -> find_lset succ_v x let get_graph (x:t) = x.graph @@ -296,7 +292,7 @@ let assert_invariants (x:t) : unit = assert (G.mem_vertex x.graph v2) in G.iter_edges assert_edge x.graph; - let assert_lmap (lv:Lval.t) (v:V.t) = + let assert_lmap (lv : lval) (v:V.t) = assert (G.mem_vertex x.graph v); assert (LSet.mem lv (VMap.find v x.vmap)) in @@ -330,11 +326,6 @@ let pretty ?(debug = false) fmt (x:t) = (** .dot printing functions*) let find_vertex_name_ref = Extlib.mk_fun "find_vertex_name" -let lset_to_string (s: LSet.t) : string = - let fmt = Format.str_formatter in - Format.fprintf fmt "\"%a\"" LSet.pretty s; - Format.flush_str_formatter () - module Dot = Graphviz.Dot (struct include G let edge_attributes _ = [] @@ -343,7 +334,9 @@ module Dot = Graphviz.Dot (struct let vertex_attributes _ = [`Shape `Box] let vertex_name (v:V.t) = let lset = !find_vertex_name_ref v in - lset_to_string lset + let fmt = Format.str_formatter in + Format.fprintf fmt "\"%a\"" LSet.pretty lset; + Format.flush_str_formatter () let default_vertex_attributes _ = [] let graph_attributes _ = [] end) @@ -364,13 +357,9 @@ let rec closure_find_lset (v:V.t) (x:t) : (V.t * LSet.t) list = | _ -> Options.fatal ("this shall not happen (invariant broken)") let find_transitive_closure (lv:lval) (x:t) : (G.V.t * LSet.t) list = - let lv: Lval.t = Lval.from_lval lv in + let lv = Lval.simplify lv in assert_invariants x; - try - let v = (LLMap.find lv x.lmap) in - closure_find_lset v x - with - Not_found -> [] + try closure_find_lset (LLMap.find lv x.lmap) x with Not_found -> [] (* TODO : what about offsets ? *) (* NOTE on "constant vertex": a constant vertex represents an unamed @@ -380,49 +369,34 @@ let find_transitive_closure (lv:lval) (x:t) : (G.V.t * LSet.t) list = lval in [lmap] *) let create_cst_vertex (x:t) : V.t * t = let new_v = fresh_node_id () in - let new_g = G.add_vertex x.graph new_v in - let new_lmap = x.lmap in - let new_vmap = VMap.add new_v LSet.empty x.vmap in - new_v , + new_v, { - graph = new_g ; - lmap = new_lmap ; - vmap = new_vmap ; + graph = G.add_vertex x.graph new_v; + lmap = x.lmap ; + vmap = VMap.add new_v LSet.empty x.vmap } (* find all the aliases of lv1 in x, for create_vertex *) -let find_all_aliases_of_offset (lv1: Lval.t) (x: t) : LSet.t = - - let list_of_lval_to_be_searched : (Lval.t*offset) list = - decompose_lval lv1 - in +let find_all_aliases_of_offset (lv1 : lval) (x: t) : LSet.t = + let lvals_to_be_searched = decompose_lval lv1 in (* for each lval, find the set of aliases *) let f_map (lv,o) = - try (VMap.find (LLMap.find lv x.lmap) x.vmap, o) - with - Not_found -> (LSet.empty,o) + try VMap.find (LLMap.find lv x.lmap) x.vmap, o + with Not_found -> LSet.empty, o in Options.debug ~level:9 "decompose_lval %a : [@[<hov 2>" Lval.pretty lv1; - List.iter (fun (x, o) -> Options.debug ~level:9 " (%a,%a) " Lval.pretty x Offset.pretty o) list_of_lval_to_be_searched; + List.iter (fun (x, o) -> Options.debug ~level:9 " (%a,%a) " Lval.pretty x Offset.pretty o) lvals_to_be_searched; Options.debug ~level:9 "@]]"; - let list_of_aliases : (LSet.t*offset) list = - List.map f_map list_of_lval_to_be_searched - in + let aliases = List.map f_map lvals_to_be_searched in (* for each lval of the Lset, add the offset and add it to the resulting set *) - let f_fold_left (acc:LSet.t) (ls,o) = - LSet.fold - (fun lv acc -> let lv = Lval.addOffsetLval o lv in LSet.add lv acc) - ls - acc + let f_fold_left (acc : LSet.t) (ls,o) = + LSet.fold (fun lv -> LSet.add @@ Cil.addOffsetLval o lv) ls acc in - List.fold_left - f_fold_left - (LSet.singleton lv1) - list_of_aliases + List.fold_left f_fold_left (LSet.singleton lv1) aliases (* returns the new vertex and the new graph *) (* only for function find_or_create vertex *) -let create_vertex_simple (lv:Lval.t) (x:t) : V.t * t = +let create_vertex_simple (lv:lval) (x:t) : V.t * t = let new_v = fresh_node_id () in let new_g = G.add_vertex x.graph new_v in (* find all the alias of lv (because of offset) *) @@ -446,7 +420,7 @@ let create_vertex_simple (lv:Lval.t) (x:t) : V.t * t = in assert_invariants new_x; match lv with - | BLval (Var v, NoOffset) -> + | Var v, NoOffset -> begin match v.vtype with TPtr _ -> @@ -454,18 +428,11 @@ let create_vertex_simple (lv:Lval.t) (x:t) : V.t * t = let another_v, new_x = create_cst_vertex new_x in let new_g = G.add_edge new_x.graph new_v another_v in new_v, {new_x with graph = new_g} - | _ -> new_v ,new_x + | _ -> new_v, new_x end - | _ -> - new_v , new_x + | _ -> new_v , new_x -(* only for function find_or_create_vertex *) -let create_vertex_addr (lv:lval) (v:V.t) (x:t) : V.t *t = - let va, x = create_vertex_simple (BAddrOf lv) x in - let new_g = G.add_edge x.graph va v in - va, { x with graph = new_g} - -let diff_offset (lv1:Lval.t) (lv2:Lval.t) = +let diff_offset (lv1 : lval) (lv2 : lval) = let rec f_diff_offset o1 o2 = match o1, o2 with NoOffset, _ -> o2 @@ -473,127 +440,100 @@ let diff_offset (lv1:Lval.t) (lv2:Lval.t) = | Index (_,o1), Index (_,o2) -> f_diff_offset o1 o2 | _ -> Options.fatal "%s: unexpected case" __LOC__ in - let _, o1 = Lval.removeOffsetLval lv1 - and _, o2 = Lval.removeOffsetLval lv2 + let _, o1 = Cil.removeOffsetLval lv1 + and _, o2 = Cil.removeOffsetLval lv2 in assert (LLMap.is_sub_offset o1 o2); f_diff_offset o1 o2 -(* create_vertex_lval shall only be called by find_or_create_vertex *) -(* creates a new vertex for a lval, assuming it is not already present - in the graph. If it is present, there will be bugs *) -let rec create_vertex_lval (blv:Lval.t) (x:t) : V.t * t = - assert (not (LLMap.mem blv x.lmap)); - Options.debug ~level:9 "creating a vertex for %a" Lval.pretty blv; - match blv with - | BLval lv -> - begin - match lv with - (Mem e, NoOffset) -> - (* special case, when we also add another vertex and a points-to edge*) - begin - (* first find the vertex corresponding to e *) - match Lval.from_exp e with - | None -> Options.fatal "unexpected result: Lval.from (%a) = None" Exp.pretty e - | Some (BLval lv1) -> - (* find the vertex *) - let v1, x = find_or_create_vertex (BLval lv1) x in - (* then creates a vertex for bvl ONLY IF there is no successor *) - begin - match G.succ x.graph v1 with - [] -> - let v2, x = create_vertex_simple blv x in - (* finally add a points-to edge between v1 and v2 *) - let new_graph = G.add_edge x.graph v1 v2 in - v2, {x with graph = new_graph } - | [succ_v1] -> - (* if there is a successor, update lmap and vmap to add blv to that successor's set *) - let new_lmap = LLMap.add blv succ_v1 x.lmap in - let new_vmap = VMap.add succ_v1 (LSet.add blv (VMap.find succ_v1 x.vmap)) x.vmap in - succ_v1, {x with lmap = new_lmap ; vmap = new_vmap } - | _ -> Options.fatal " Invariant violated : more than 1 successor" - end - | Some (BAddrOf lv) -> find_or_create_vertex (BLval lv) x - end - | _ -> create_vertex_simple blv x - end - | BAddrOf lv -> - let v1, x = find_or_create_vertex (BLval lv) x in - create_vertex_addr lv v1 x +let rec create_vertex lv x = + Options.debug ~level:9 "creating a vertex for %a" Lval.pretty lv; + assert (not (LLMap.mem lv x.lmap)); + begin + match lv with + (Mem e, NoOffset) -> + (* special case, when we also add another vertex and a points-to edge*) + begin + (* first find the vertex corresponding to e *) + match LvalOrRef.from_exp e with + | None -> Options.fatal "unexpected result: Lval.from (%a) = None" Exp.pretty e + | Some (LvalOrRef.Ref _) -> Options.fatal "unexpected: *(&x)" + | Some (LvalOrRef.Lval lv1) -> + (* find the vertex *) + let v1, x = find_or_create_vertex (LvalOrRef.Lval lv1) x in + (* then creates a vertex for bvl ONLY IF there is no successor *) + begin + match G.succ x.graph v1 with + [] -> + let v2, x = create_vertex_simple lv x in + (* finally add a points-to edge between v1 and v2 *) + let new_graph = G.add_edge x.graph v1 v2 in + v2, {x with graph = new_graph } + | [succ_v1] -> + (* if there is a successor, update lmap and vmap to add blv to that successor's set *) + let new_lmap = LLMap.add lv succ_v1 x.lmap in + let new_vmap = VMap.add succ_v1 (LSet.add lv (VMap.find succ_v1 x.vmap)) x.vmap in + succ_v1, {x with lmap = new_lmap ; vmap = new_vmap } + | _ -> Options.fatal " Invariant violated : more than 1 successor" + end + end + | _ -> create_vertex_simple lv x + end + +and find_or_create_lval_vertex (lv:lval) (x:t) : V.t * t = + try LLMap.find lv x.lmap, x + with Not_found -> + (* try to find if an alias already exists in x *) + let map_predecessors : V.t LMap.t = + LLMap.find_upper_offsets lv x.lmap + in + (* for any predecessor, find all its aliases and then look for potential existing vertex *) + let f_fold_lmap lvx vx acc = + let set_aliases = VMap.find vx x.vmap in + Options.debug ~level:9 "looking for aliases of %a in set %a" Lval.pretty lv LSet.pretty set_aliases; + if LSet.cardinal set_aliases <= 1 then acc else + let off = diff_offset lvx lv in + let f_fold_lset lvs acc = + try + let lvs = Cil.addOffsetLval off lvs in + VSet.add (LLMap.find lvs x.lmap) acc + with + Not_found -> acc + in + LSet.fold f_fold_lset set_aliases acc + in + (* set of all existing aliases *) + let vset_res = LMap.fold f_fold_lmap map_predecessors VSet.empty in + Options.debug ~level:9 "found aliases of %a : %a" Lval.pretty lv VSet.pretty vset_res; + if VSet.is_empty vset_res + then create_vertex lv x + else + let () = assert (VSet.cardinal vset_res = 1) in + let v_res = VSet.choose vset_res in + (* vertex found, update the tables *) + let new_lmap = LLMap.add lv v_res x.lmap in + let new_vmap = VMap.add v_res (LSet.add lv (VMap.find v_res x.vmap)) x.vmap in + v_res, {x with lmap = new_lmap; vmap = new_vmap} (* find the vertex of an lval *) -and find_or_create_vertex (lv:Lval.t) (x:t) : V.t * t = - try (LLMap.find lv x.lmap, x) - with - Not_found -> - begin - (* try to find if an alias already exists in x *) - let map_predecessors :V.t LMap.t = LLMap.find_upper_offsets lv x.lmap in - (* for any predecessor, find all its aliases and then look for potential existing vertex *) - let f_fold_lmap lvx vx acc = - let set_aliases = VMap.find vx x.vmap in - Options.debug ~level:9 "looking for aliases of %a in set %a" Lval.pretty lv LSet.pretty set_aliases; - if LSet.cardinal set_aliases > 1 - then - let off = diff_offset lvx lv in - let f_fold_lset lvs acc = - try - let lvs = Lval.addOffsetLval off lvs in - VSet.add (LLMap.find lvs x.lmap) acc - with - Not_found -> acc - in - LSet.fold - f_fold_lset - set_aliases - acc - else - acc - in - (* set of all existing aliases *) - let vset_res = - LMap.fold - f_fold_lmap - map_predecessors - VSet.empty - in - Options.debug ~level:9 "found aliases of %a : %a" Lval.pretty lv VSet.pretty vset_res; - if VSet.is_empty vset_res - then create_vertex_lval lv x - else - begin - assert (VSet.cardinal vset_res = 1); - let v_res = VSet.choose vset_res in - (* vertex found, update the tables *) - let new_lmap = LLMap.add lv v_res x.lmap in - let new_vmap = VMap.add v_res (LSet.add lv (VMap.find v_res x.vmap)) x.vmap in - v_res, {x with lmap = new_lmap; vmap = new_vmap} - end - end +and find_or_create_vertex (lv : LvalOrRef.t) (x:t) : V.t * t = + match lv with + | LvalOrRef.Lval lv -> find_or_create_lval_vertex lv x + | LvalOrRef.Ref lv -> + Options.debug ~level:9 "creating a vertex for %a" LvalOrRef.pretty (LvalOrRef.Ref lv); + let v1, x = find_or_create_lval_vertex lv x in + let va, x = create_cst_vertex x in + va, {x with graph = G.add_edge x.graph va v1} (* TODO is there a better way to do it ? *) let find_vertex lv x = - let lv = Lval.from_lval lv in - let v,x1 = find_or_create_vertex lv x in + let lv = Lval.simplify lv in + let v,x1 = find_or_create_lval_vertex lv x in if x == x1 (* if x has not been modified, then the vertex was found, not created *) then v else raise Not_found -(* remove a lval from a graph*) -let remove_lval (x:t) (lv:Lval.t) :t = - assert_invariants x; - try - let v = LLMap.find lv x.lmap in - let setv = VMap.find v x.vmap in - let new_lmap = LLMap.remove lv x.lmap in - let new_vmap = VMap.add v (LSet.remove lv setv) x.vmap in - let result = {x with lmap = new_lmap; vmap = new_vmap} in - assert_invariants result; - result - with - Not_found -> x - (* merge of two vertices; the first vertex carries both sets, the second is removed from the graph and from lmap and vmap *) let merge x v1 v2 = if (V.equal v1 v2) || not (G.mem_vertex x.graph v1) || not (G.mem_vertex x.graph v2) @@ -697,13 +637,12 @@ let set_type (x:t) (v1:V.t) (v2:V.t) : t = let assignment (a:t) (lv:lval) (e:exp) : t = assert_invariants a; - if Cil.isPointerType (Cil.typeOf e) - then - let x = Lval.from_lval lv in - match Lval.from_exp e with + if not @@ Cil.isPointerType (Cil.typeOf e) then a else + let x = Lval.simplify lv in + match LvalOrRef.from_exp e with | None -> a | Some y -> - let (v1,a) = find_or_create_vertex x a in + let (v1,a) = find_or_create_lval_vertex x a in let (v2,a) = find_or_create_vertex y a in if List.mem v2 (G.succ a.graph v1) || List.mem v1 (G.succ a.graph v2) then @@ -714,27 +653,19 @@ let assignment (a:t) (lv:lval) (e:exp) : t = in a else let a = join a v1 v2 in - let a = match y with - | BAddrOf blv -> remove_lval a (BAddrOf blv) - | _ -> a - in let () = assert_invariants a in a - else - a (* assignment x = allocate(y) *) let assignment_x_allocate_y (a:t) (lv:lval) : t = assert_invariants a; - let x = Lval.from_lval lv in - let (v1,a) = find_or_create_vertex x a in + let x = Lval.simplify lv in + let (v1,a) = find_or_create_lval_vertex x a in match G.succ a.graph v1 with - [] -> - begin - let (v2,a) = create_cst_vertex a in - let new_a : t = set_type a v1 v2 in - assert_invariants new_a ; new_a - end + | [] -> + let (v2,a) = create_cst_vertex a in + let new_a : t = set_type a v1 v2 in + let () = assert_invariants new_a in new_a | [_v2] -> a | _ -> Options.fatal "this should not hapen (invariant broken)" @@ -745,7 +676,7 @@ let is_included (a1:t) (a2:t) = Options.debug ~level:8 "testing equal %a AND à .%a" (pretty ~debug:true) a1 (pretty ~debug:true) a2; let exception Not_included in try - let iter_lmap (lv:Lval.t) (v1:V.t): unit = + let iter_lmap (lv : lval) (v1:V.t): unit = let v2 : V.t = try LLMap.find lv a2.lmap with Not_found -> raise Not_included in match G.succ a1.graph v1, G.succ a2.graph v2 with [], _ -> () @@ -903,7 +834,7 @@ let make_summary (s : t) (kf : kernel_function) = None -> s | Some e -> begin - match s, Lval.from_exp e with + match s, LvalOrRef.from_exp e with _, None -> s | s, Some lv -> let _, new_s = find_or_create_vertex lv s in @@ -918,11 +849,15 @@ let make_summary (s : t) (kf : kernel_function) = } let pretty_summary ?(debug=false) fmt s = - let print_list_lval fmt (l: lval list) = + let print_list_lval ~state fmt (l: lval list) = let is_first = ref true in let print_elem x = - if !is_first then is_first := false else Format.fprintf fmt "@ "; - Format.fprintf fmt "%a" Cil_datatype.Lval.pretty x + if !is_first then is_first := false else Format.fprintf fmt "@ "; + Format.fprintf fmt "@[%a" Cil_datatype.Lval.pretty x; + let pointees = points_to_set x state in + if not @@ LSet.is_empty pointees then + Format.fprintf fmt "→%a" LSet.pretty pointees; + Format.fprintf fmt "@]"; in List.iter print_elem l in @@ -934,11 +869,11 @@ let pretty_summary ?(debug=false) fmt s = match s.state with | None -> if debug then Format.fprintf fmt "not found" | Some s when is_empty s -> if debug then Format.fprintf fmt "empty" - | _ -> + | Some state -> begin - Format.fprintf fmt "@[formals: @[%a@]@;<3>locals: @[%a@]@;<3>returns: @[%a@]@;<3>state: @[%a@] " - print_list_lval s.formals - print_list_lval s.locals + Format.fprintf fmt "@[formals: @[%a@]@;<4>locals: @[%a@]@;<4>returns: @[%a@]@;<4>state: @[%a@] " + (print_list_lval ~state) s.formals + (print_list_lval ~state) s.locals (print_option Exp.pretty) s.return (print_option @@ pretty ~debug) s.state; end @@ -959,16 +894,20 @@ let call (state:t) (res:lval option) (args:exp list) (summary:summary) :t = let res_ret = match res, summary.return with | None, None -> [] | Some res, Some ret -> - [Simplified_lval.from_lval res, Option.get @@ Simplified_lval.from_exp ret] + let simplify_ret x = match LvalOrRef.from_exp x with + | Some (LvalOrRef.Lval lval) -> lval + | _ -> Options.fatal "unexpected form of return statement" + in + [LvalOrRef.Lval (Lval.simplify res), simplify_ret ret] | None, Some _ -> [] | Some _, None -> (* Shouldn't happen: Frama-C adds missing returns *) Options.fatal "unexpected case: result without return" in let simplify_both (arg, formal) = try - match Lval.from_exp arg with + match LvalOrRef.from_exp arg with | None -> None - | Some lv -> Some (lv, Simplified_lval.from_lval formal) + | Some lv -> Some (lv, Lval.simplify formal) with Explicit_pointer_address loc -> Options.warning ~source:(fst loc) ~wkey:Options.Warn.unsupported_address "unsupported feature: explicit pointer address: %a; analysis may be unsound" @@ -1027,5 +966,6 @@ let call (state:t) (res:lval option) (args:exp list) (summary:summary) :t = in let state = List.fold_left join_succs state (List.map fst vertex_pairs) in + assert_invariants state; state diff --git a/src/plugins/alias/abstract_state.mli b/src/plugins/alias/abstract_state.mli index a3a843f817276e33cca790ed9facc5a4f34118fe..8506611bc0f61251f5ee4b60f44506145c9fff96 100644 --- a/src/plugins/alias/abstract_state.mli +++ b/src/plugins/alias/abstract_state.mli @@ -27,9 +27,21 @@ open Cil_types (** Points-to graphs datastructure. *) module G: Graph.Sig.G -(** NB : type Lval.t is not the same as type lval !! *) -module LSet = Simplified.Simplified_lset +(** Set of [lval]s. Differs from Cil_datatype.Lval.Set in that is uses a + different comparison function ([Cil_datatype.LvalStructEq.compare]). *) +module LSet : sig + include Set.S with type elt = lval + val pretty: Format.formatter -> t -> unit +end + +(** map of [lval]s. Differs from Cil_datatype.Lval.Met in that is uses a + different comparison function ([Cil_datatype.LvalStructEq.compare]). *) +module LMap : sig + include Map.S with type key = lval + + val pretty: (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a t -> unit +end (** external signature *) module type S = @@ -66,6 +78,9 @@ sig other vertex of the graph *) val find_all_aliases : lval -> t -> LSet.t + (** the set of all lvars to which the given variable may point. *) + val points_to_set : lval -> t -> LSet.t + (** find_aliases, then recursively finds other sets of lvals. We have the property (if lval [lv] is in abstract state [x]) : List.hd (find_transitive_closure lv x) = (find_vertex lv x, diff --git a/src/plugins/alias/analysis.ml b/src/plugins/alias/analysis.ml index b966e32c2e830481a385a4fd089378364c972ec7..148dabcd63c02521a4a2059b661b4b21af6b5c60 100644 --- a/src/plugins/alias/analysis.ml +++ b/src/plugins/alias/analysis.ml @@ -252,16 +252,14 @@ let doFunction (kf:kernel_function) = (Abstract_state.pretty_summary ~debug:false) summary; Some summary in - if Kernel_function.is_main kf then - let f_name = Options.Dot_output.get () in - begin match f_name, final_state with - | "", _ -> () - | _, None -> () - | _, Some final_state -> Abstract_state.print_dot f_name final_state - end; - None - else - (Function_table.add kf result; result) + if Kernel_function.is_main kf then begin + match Options.Dot_output.get (), final_state with + | "", _ -> () + | _, None -> () + | fname, Some final_state -> Abstract_state.print_dot fname final_state + end; + Function_table.add kf result; + result let () = function_compute_ref := doFunction diff --git a/src/plugins/alias/simplified.ml b/src/plugins/alias/simplified.ml index a396f4bd21bb96cf7df37eeef6e4e870517d996f..8250af8e229b46ebca8acba3184ef2e89bcafaad 100644 --- a/src/plugins/alias/simplified.ml +++ b/src/plugins/alias/simplified.ml @@ -21,21 +21,15 @@ (**************************************************************************) open Cil_types - open Cil_datatype -let nul_exp= - let loc = Location.unknown in - Cil.zero ~loc - +let nul_exp= Cil.zero ~loc:Location.unknown let is_nul_exp = Cil_datatype.ExpStructEq.equal nul_exp module HL = Lval.Hashtbl - module HE = Exp.Hashtbl let cached_lval = HL.create 23 - let cached_exp = HE.create 37 let clear_cache () = @@ -55,6 +49,12 @@ let check_cast_compatibility e typ = "unsafe cast from %a to %a" Printer.pp_typ type_of_e Printer.pp_typ typ +let rec simplify_offset o = + match o with + | NoOffset -> NoOffset + | Field(f,o) -> Field(f, simplify_offset o) + | Index(_e,o) -> Index(nul_exp, simplify_offset o) + let rec simplify_lval (h,o) = try HL.find cached_lval (h,o) with Not_found -> @@ -71,12 +71,6 @@ and simplify_host h = then raise (Explicit_pointer_address e.eloc) else Mem simp_e -and simplify_offset o = - match o with - | NoOffset -> NoOffset - | Field(f,o) -> Field(f, simplify_offset o) - | Index(_e,o) -> Index(nul_exp, simplify_offset o) - and simplify_exp e = try HE.find cached_exp e @@ -99,118 +93,52 @@ and simplify_exp e = HE.add cached_exp e res; res -type simplified_lval = - | BLval of lval - | BAddrOf of lval - -module Simplified_lval = struct - - type t = simplified_lval - - let from_lval lv = - BLval (simplify_lval lv) - - let from_exp e = - let e = simplify_exp e in - match e.enode with - Lval lv -> Some (BLval lv) - | AddrOf lv -> Some (BAddrOf lv) - | _ -> None - - let compare x1 x2 = - match (x1,x2) with - | (BLval lv1, BLval lv2) -> Cil_datatype.LvalStructEq.compare lv1 lv2 - | (BLval _, _) -> -1 - | (_, BLval _) -> 1 - | (BAddrOf lv1, BAddrOf lv2) -> Cil_datatype.LvalStructEq.compare lv1 lv2 - - let print f fmt x = - match x with - | BLval lv -> f fmt lv - | BAddrOf lv -> Format.fprintf fmt "&%a" f lv +module LvalOrRef = struct + type t = Lval of lval | Ref of lval let pretty l = + let print f fmt x = + match x with + | Lval lv -> f fmt lv + | Ref lv -> Format.fprintf fmt "&%a" f lv + in if Options.is_debug_key_enabled Options.DebugKeys.lvals then print Cil_types_debug.pp_lval l else print Printer.pp_lval l - let removeOffsetLval x = - match x with - | BLval lv -> let lv,o = Cil.removeOffsetLval lv in BLval lv, o - | BAddrOf lv -> let lv,o = Cil.removeOffsetLval lv in BAddrOf lv, o - - let addOffsetLval o x = - match x with - | BLval lv -> let lv = Cil.addOffsetLval o lv in BLval lv - | BAddrOf lv -> let lv = Cil.addOffsetLval o lv in BAddrOf lv - - let points_to x = - match x with - | BAddrOf lv -> BLval lv - | BLval lv -> - BLval (Mem (Cil.dummy_exp (Lval lv)), NoOffset) + let from_exp e = + let e = simplify_exp e in + match e.enode with + Lval lv -> Some (Lval lv) + | AddrOf lv -> Some (Ref lv) + | _ -> None let is_pointer x = match x with - | BAddrOf _ -> true - | BLval lv -> + | Ref _ -> true + | Lval lv -> let t = Cil.typeOfLval lv in match Cil.unrollType t with TPtr _ | TArray _ -> true | _ -> false end -module Simplified_lmap = -struct - include Map.Make (Simplified_lval) - - let print (f_key: Format.formatter -> key -> unit) (f_val : Format.formatter -> 'a -> unit) fmt (m: 'a t) = - let is_first = ref true in - Format.fprintf fmt "{@[<hov 2>"; - iter (fun k v -> - if not !is_first - then - Format.fprintf fmt ",@," - else - is_first := false; - Format.fprintf fmt " %a -> %a" f_key k f_val v - ) - m; - Format.fprintf fmt " @]}" - - let pretty f fmt m = print Simplified_lval.pretty f fmt m -end +module Lval = struct + type t = lval -module Simplified_lset = -struct - include Set.Make (Simplified_lval) - - let print (f_elt: Format.formatter -> elt -> unit) fmt (m: t) = - let is_first = ref true in - Format.fprintf fmt "{@["; - iter (fun e -> - if !is_first - then - is_first := false - else - Format.fprintf fmt ",@ "; - Format.fprintf fmt "%a" f_elt e - ) - m; - Format.fprintf fmt "@]}" - - let pretty fmt s = print Simplified_lval.pretty fmt s - - let fold_lval f s init = - let f_fold lv acc = - match lv with - | BLval lv -> f lv acc - | BAddrOf lv -> f lv acc - in - fold f_fold s init + let simplify x = simplify_lval x + + let compare = Cil_datatype.LvalStructEq.compare + + let pretty l = + if Options.is_debug_key_enabled Options.DebugKeys.lvals + then Cil_types_debug.pp_lval l + else Printer.pp_lval l + + let points_to lv = Mem (Cil.dummy_exp (Lval lv)), NoOffset end -let decompose_lval (lv1: Simplified_lval.t) : (Simplified_lval.t*offset) list = +let decompose_lval lv1 : (lval * offset) list = let rec list_of_offset (o: offset) : (offset*offset) list = match o with NoOffset -> [NoOffset,o] @@ -229,8 +157,7 @@ let decompose_lval (lv1: Simplified_lval.t) : (Simplified_lval.t*offset) list = in (NoOffset,o)::li in - let lv, off = Simplified_lval.removeOffsetLval lv1 in + let lv, off = Cil.removeOffsetLval lv1 in List.map - (fun (o1,o2) -> (Simplified_lval.addOffsetLval o1 lv,o2)) + (fun (o1,o2) -> Cil.addOffsetLval o1 lv, o2) (list_of_offset off) - diff --git a/src/plugins/alias/simplified.mli b/src/plugins/alias/simplified.mli index 499038fdebf073fe7c01b0342616a3f639ac5c89..08f5e21c9e8d1785115db6de5160d856c54b7360 100644 --- a/src/plugins/alias/simplified.mli +++ b/src/plugins/alias/simplified.mli @@ -22,62 +22,37 @@ open Cil_types -type simplified_lval = - | BLval of lval (* lval *) - | BAddrOf of lval (* address *) - -(* exception raised when the program tries to access a memory location directly. *) -exception Explicit_pointer_address of location - -module Simplified_lval: -sig - type t = simplified_lval - - val compare: t -> t -> int +module LvalOrRef : sig + type t = Lval of lval | Ref of lval + val pretty : Format.formatter -> t -> unit (* result stored in cache. May raise Explicit_pointer_address *) - val from_lval: lval -> t - - (* result stored in cache. May raise Explicit_pointer_address *) - val from_exp: exp -> t option - - val pretty: Format.formatter -> t -> unit - - (* maps !Cil.removeOffsetLval to simplified_lval *) - val removeOffsetLval : t -> t * offset - - (* maps !Cil.addOffsetLval to simplified_lval *) - val addOffsetLval : offset -> t -> t - - (* (points_to x) = *x and (points_to &x) = x. Raise - Explicit_pointer_address when applied to BNone *) - val points_to : t -> t + val from_exp : exp -> t option (* true if x is assimilable to a pointer type (explicit pointer or memory adress or array *) val is_pointer : t -> bool end -module Simplified_lmap: -sig - include Map.S with type key = Simplified_lval.t +(* exception raised when the program tries to access a memory location directly. *) +exception Explicit_pointer_address of location + +module Lval : sig + type t = lval - val pretty: (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a t -> unit -end + val compare: t -> t -> int -module Simplified_lset: -sig - include Set.S with type elt = Simplified_lval.t + (* result stored in cache. May raise Explicit_pointer_address *) + val simplify : lval -> lval val pretty: Format.formatter -> t -> unit - (* special fold *) - val fold_lval : (lval -> 'a -> 'a) -> t -> 'a -> 'a - + (* (points_to x) = *x and (points_to &x) = x. Raise + Explicit_pointer_address when applied to BNone *) + val points_to : lval -> lval end -val decompose_lval : Simplified_lval.t -> (Simplified_lval.t*offset) list +val decompose_lval : lval -> (lval * offset) list (** clear the two caches *) val clear_cache : unit -> unit - diff --git a/src/plugins/alias/tests/basic/oracle/function4.res.oracle b/src/plugins/alias/tests/basic/oracle/function4.res.oracle index 45fcb1233288f772757cf41cb588a61287b17484..b7e6c7adde41156fd688fe72ca19bc4252f34c0d 100644 --- a/src/plugins/alias/tests/basic/oracle/function4.res.oracle +++ b/src/plugins/alias/tests/basic/oracle/function4.res.oracle @@ -9,7 +9,7 @@ [alias] analysing instruction: int c = 0; [alias] May-aliases after instruction int c = 0; are <none> [alias] analysing instruction: a = addr(& c); -[alias] May-aliases after instruction a = addr(& c); are {a, &c} +[alias] May-aliases after instruction a = addr(& c); are <none> [alias] analysing instruction: b = & c; [alias] May-aliases after instruction b = & c; are {a, b} [alias] analysing instruction: __retres = 0; diff --git a/src/plugins/alias/tests/real_world/oracle/function1_v2.res.oracle b/src/plugins/alias/tests/real_world/oracle/function1_v2.res.oracle index 5a63a549c73983681d3129eca2bb7d2d3191a2a3..029211f36e3c5e5788b1656bc41836f8e6628d8b 100644 --- a/src/plugins/alias/tests/real_world/oracle/function1_v2.res.oracle +++ b/src/plugins/alias/tests/real_world/oracle/function1_v2.res.oracle @@ -61,12 +61,12 @@ [alias] analysing instruction: *b = 42; [alias] May-aliases after instruction *b = 42; are <none> [alias] analysing instruction: alias(& a,& b); -[alias] May-aliases after instruction alias(& a,& b); are {&a, &b} {a, b} +[alias] May-aliases after instruction alias(& a,& b); are {a, b} [alias] analysing instruction: *a = 7; -[alias] May-aliases after instruction *a = 7; are {&a, &b} {a, b} +[alias] May-aliases after instruction *a = 7; are {a, b} [alias] analysing instruction: __retres = 0; -[alias] May-aliases after instruction __retres = 0; are {&a, &b} {a, b} -[alias] May-aliases at the end of function main: {&a, &b} {a, b} +[alias] May-aliases after instruction __retres = 0; are {a, b} +[alias] May-aliases at the end of function main: {a, b} [alias] analysing function: malloc [alias] May-aliases at the end of function malloc: ⊥ [alias] analysing function: mblen