[racerd] remove ownership precondition module

Summary: This module mirrors `OwnershipAbstractValue`.  Its removal also allows simplifying `add_callee_accesses` significantly.

Reviewed By: jberdine

Differential Revision: D20563938

fbshipit-source-id: 36abca2d0
master
Nikos Gorogiannis 5 years ago committed by Facebook GitHub Bot
parent e3da644776
commit a2428a11e3

@ -40,7 +40,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
else else
let is_write = List.is_empty access_list && is_write_access in let is_write = List.is_empty access_list && is_write_access in
let access = TraceElem.make_field_access prefix_path' ~is_write loc in let access = TraceElem.make_field_access prefix_path' ~is_write loc in
let pre = OwnershipDomain.get_precondition prefix_path ownership in let pre = OwnershipDomain.get_owned prefix_path ownership in
let snapshot_opt = AccessSnapshot.make formals access locks threads pre in let snapshot_opt = AccessSnapshot.make formals access locks threads pre in
let access_acc' = AccessDomain.add_opt snapshot_opt acc in let access_acc' = AccessDomain.add_opt snapshot_opt acc in
add_field_accesses prefix_path' access_acc' access_list add_field_accesses prefix_path' access_acc' access_list
@ -59,7 +59,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
let container_access = let container_access =
TraceElem.make_container_access receiver_ap ~is_write callee_pname callee_loc TraceElem.make_container_access receiver_ap ~is_write callee_pname callee_loc
in in
let ownership_pre = OwnershipDomain.get_precondition receiver_ap astate.ownership in let ownership_pre = OwnershipDomain.get_owned receiver_ap astate.ownership in
AccessSnapshot.make formals container_access astate.locks astate.threads ownership_pre AccessSnapshot.make formals container_access astate.locks astate.threads ownership_pre
in in
let ownership_value = OwnershipDomain.get_owned receiver_ap astate.ownership in let ownership_value = OwnershipDomain.get_owned receiver_ap astate.ownership in
@ -118,33 +118,19 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
let add_callee_accesses formals (caller_astate : Domain.t) callee_accesses locks threads actuals let add_callee_accesses formals (caller_astate : Domain.t) callee_accesses locks threads actuals
callee_pname loc = callee_pname loc =
let open Domain in let open Domain in
let conjoin_ownership_precondition actual_indexes actual_exp : let update_ownership_precondition actual_index (acc : OwnershipAbstractValue.t) =
AccessSnapshot.OwnershipPrecondition.t =
match actual_exp with
| HilExp.Constant _ ->
(* the actual is a constant, so it's owned in the caller. *)
Conjunction actual_indexes
| HilExp.AccessExpression access_expr -> (
match OwnershipDomain.get_owned access_expr caller_astate.ownership with
| OwnedIf formal_indexes ->
(* conditionally owned if [formal_indexes] are owned *)
Conjunction (IntSet.union formal_indexes actual_indexes)
| Unowned ->
(* not rooted in a formal and not conditionally owned *)
False )
| _ ->
(* couldn't find access expr, don't know if it's owned. assume not *)
False
in
let update_ownership_precondition actual_index (acc : AccessSnapshot.OwnershipPrecondition.t) =
match acc with match acc with
| False -> | Unowned ->
(* precondition can't be satisfied *) (* optimisation -- already unowned, don't compute ownership of remaining actuals *)
acc
| actuals_ownership -> (
match List.nth actuals actual_index with
| None ->
(* vararg methods can result into missing actuals so simply ignore *)
acc acc
| Conjunction actual_indexes -> | Some actual_exp ->
List.nth actuals actual_index OwnershipDomain.ownership_of_expr actual_exp caller_astate.ownership
(* optional args can result into missing actuals so simply ignore *) |> OwnershipAbstractValue.join actuals_ownership )
|> Option.value_map ~default:acc ~f:(conjoin_ownership_precondition actual_indexes)
in in
let update_callee_access (snapshot : AccessSnapshot.t) acc = let update_callee_access (snapshot : AccessSnapshot.t) acc =
let access = TraceElem.with_callsite snapshot.access (CallSite.make callee_pname loc) in let access = TraceElem.with_callsite snapshot.access (CallSite.make callee_pname loc) in
@ -155,18 +141,11 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
(* update precondition with caller ownership info *) (* update precondition with caller ownership info *)
let ownership_precondition = let ownership_precondition =
match snapshot.ownership_precondition with match snapshot.ownership_precondition with
| Conjunction indexes -> | OwnedIf indexes ->
let empty_precondition = IntSet.fold update_ownership_precondition indexes OwnershipAbstractValue.owned
AccessSnapshot.OwnershipPrecondition.Conjunction IntSet.empty | Unowned ->
in
IntSet.fold update_ownership_precondition indexes empty_precondition
| False ->
snapshot.ownership_precondition snapshot.ownership_precondition
in in
if AccessSnapshot.OwnershipPrecondition.is_true ownership_precondition then
(* discard accesses to owned memory *)
acc
else
let snapshot_opt = AccessSnapshot.make formals access locks thread ownership_precondition in let snapshot_opt = AccessSnapshot.make formals access locks thread ownership_precondition in
AccessDomain.add_opt snapshot_opt acc AccessDomain.add_opt snapshot_opt acc
in in

@ -260,32 +260,63 @@ module ThreadsDomain = struct
match callee_astate with AnyThreadButSelf -> callee_astate | _ -> caller_astate match callee_astate with AnyThreadButSelf -> callee_astate | _ -> caller_astate
end end
module AccessSnapshot = struct module OwnershipAbstractValue = struct
module OwnershipPrecondition = struct type t = OwnedIf of IntSet.t | Unowned [@@deriving compare]
type t = Conjunction of IntSet.t | False [@@deriving compare]
let owned = OwnedIf IntSet.empty
let is_owned = function OwnedIf set -> IntSet.is_empty set | _ -> false
let unowned = Unowned
let make_owned_if formal_index = OwnedIf (IntSet.singleton formal_index)
let leq ~lhs ~rhs =
phys_equal lhs rhs
||
match (lhs, rhs) with
| _, Unowned ->
true (* Unowned is top *)
| Unowned, _ ->
false
| OwnedIf s1, OwnedIf s2 ->
IntSet.subset s1 s2
(* precondition is true if the conjunction of owned indexes is empty *) let join astate1 astate2 =
let is_true = function False -> false | Conjunction set -> IntSet.is_empty set if phys_equal astate1 astate2 then astate1
else
match (astate1, astate2) with
| _, Unowned | Unowned, _ ->
Unowned
| OwnedIf s1, OwnedIf s2 ->
OwnedIf (IntSet.union s1 s2)
let widen ~prev ~next ~num_iters:_ = join prev next
let pp fmt = function let pp fmt = function
| Conjunction indexes -> | Unowned ->
F.fprintf fmt "Owned(%a)" F.pp_print_string fmt "Unowned"
| OwnedIf s ->
if IntSet.is_empty s then F.pp_print_string fmt "Owned"
else
F.fprintf fmt "OwnedIf%a"
(PrettyPrintable.pp_collection ~pp_item:Int.pp) (PrettyPrintable.pp_collection ~pp_item:Int.pp)
(IntSet.elements indexes) (IntSet.elements s)
| False ->
F.pp_print_string fmt "False"
end end
module AccessSnapshot = struct
type t = type t =
{ access: TraceElem.t { access: TraceElem.t
; thread: ThreadsDomain.t ; thread: ThreadsDomain.t
; lock: bool ; lock: bool
; ownership_precondition: OwnershipPrecondition.t } ; ownership_precondition: OwnershipAbstractValue.t }
[@@deriving compare] [@@deriving compare]
let make_if_not_owned formals access lock thread ownership_precondition = let make_if_not_owned formals access lock thread ownership_precondition =
if if
(not (OwnershipPrecondition.is_true ownership_precondition)) (not (OwnershipAbstractValue.is_owned ownership_precondition))
&& TraceElem.should_keep formals access && TraceElem.should_keep formals access
then Some {access; lock; thread; ownership_precondition} then Some {access; lock; thread; ownership_precondition}
else None else None
@ -303,13 +334,13 @@ module AccessSnapshot = struct
let is_unprotected {thread; lock; ownership_precondition} = let is_unprotected {thread; lock; ownership_precondition} =
(not (ThreadsDomain.is_any_but_self thread)) (not (ThreadsDomain.is_any_but_self thread))
&& (not lock) && (not lock)
&& not (OwnershipPrecondition.is_true ownership_precondition) && not (OwnershipAbstractValue.is_owned ownership_precondition)
let pp fmt {access; thread; lock; ownership_precondition} = let pp fmt {access; thread; lock; ownership_precondition} =
F.fprintf fmt "Loc: %a Access: %a Thread: %a Lock: %b Pre: %a" Location.pp F.fprintf fmt "Loc: %a Access: %a Thread: %a Lock: %b Pre: %a" Location.pp
(TraceElem.get_loc access) TraceElem.pp access ThreadsDomain.pp thread lock (TraceElem.get_loc access) TraceElem.pp access ThreadsDomain.pp thread lock
OwnershipPrecondition.pp ownership_precondition OwnershipAbstractValue.pp ownership_precondition
end end
module AccessDomain = struct module AccessDomain = struct
@ -327,50 +358,6 @@ module AccessDomain = struct
Option.fold snapshot_opt ~init:astate ~f:(fun acc s -> add s acc) Option.fold snapshot_opt ~init:astate ~f:(fun acc s -> add s acc)
end end
module OwnershipAbstractValue = struct
type t = OwnedIf of IntSet.t | Unowned [@@deriving compare]
let owned = OwnedIf IntSet.empty
let unowned = Unowned
let make_owned_if formal_index = OwnedIf (IntSet.singleton formal_index)
let leq ~lhs ~rhs =
phys_equal lhs rhs
||
match (lhs, rhs) with
| _, Unowned ->
true (* Unowned is top *)
| Unowned, _ ->
false
| OwnedIf s1, OwnedIf s2 ->
IntSet.subset s1 s2
let join astate1 astate2 =
if phys_equal astate1 astate2 then astate1
else
match (astate1, astate2) with
| _, Unowned | Unowned, _ ->
Unowned
| OwnedIf s1, OwnedIf s2 ->
OwnedIf (IntSet.union s1 s2)
let widen ~prev ~next ~num_iters:_ = join prev next
let pp fmt = function
| Unowned ->
F.pp_print_string fmt "Unowned"
| OwnedIf s ->
if IntSet.is_empty s then F.pp_print_string fmt "Owned"
else
F.fprintf fmt "OwnedIf%a"
(PrettyPrintable.pp_collection ~pp_item:Int.pp)
(IntSet.elements s)
end
module OwnershipDomain = struct module OwnershipDomain = struct
include AbstractDomain.Map (AccessExpression) (OwnershipAbstractValue) include AbstractDomain.Map (AccessExpression) (OwnershipAbstractValue)
@ -426,16 +413,6 @@ module OwnershipDomain = struct
IntSet.fold get_ownership formal_indexes OwnershipAbstractValue.owned IntSet.fold get_ownership formal_indexes OwnershipAbstractValue.owned
in in
add ret_access_exp ret_ownership_wrt_actuals ownership add ret_access_exp ret_ownership_wrt_actuals ownership
let get_precondition exp t =
match get_owned exp t with
| OwnedIf formal_indexes ->
(* access expression conditionally owned if [formal_indexes] are owned *)
AccessSnapshot.OwnershipPrecondition.Conjunction formal_indexes
| Unowned ->
(* access expression not rooted in a formal and not conditionally owned *)
AccessSnapshot.OwnershipPrecondition.False
end end
module Attribute = struct module Attribute = struct
@ -582,5 +559,5 @@ let pp fmt {threads; locks; accesses; ownership; attribute_map} =
let add_unannotated_call_access formals pname loc (astate : t) = let add_unannotated_call_access formals pname loc (astate : t) =
let access = TraceElem.make_unannotated_call_access pname loc in let access = TraceElem.make_unannotated_call_access pname loc in
let snapshot = AccessSnapshot.make formals access astate.locks astate.threads False in let snapshot = AccessSnapshot.make formals access astate.locks astate.threads Unowned in
{astate with accesses= AccessDomain.add_opt snapshot astate.accesses} {astate with accesses= AccessDomain.add_opt snapshot astate.accesses}

@ -83,27 +83,30 @@ module ThreadsDomain : sig
(** integrate current state with a callee summary *) (** integrate current state with a callee summary *)
end end
(** snapshot of the relevant state at the time of a heap access: concurrent thread(s), lock(s) held, module OwnershipAbstractValue : sig
ownership precondition *) type t = private
module AccessSnapshot : sig | OwnedIf of IntSet.t
(** precondition for owned access; access is owned if it evaluates to true *) (** Owned if the formals at the given indexes are owned in the caller; unconditionally owned
module OwnershipPrecondition : sig if the set of formals is empty = bottom of the lattice *)
type t = | Unowned (** Unowned value; top of the lattice *)
| Conjunction of IntSet.t
(** Conjunction of "formal index must be owned" predicates. true if empty *)
| False
include PrettyPrintable.PrintableOrderedType with type t := t val owned : t
val is_true : t -> bool val is_owned : t -> bool
(** return [true] if the precondition evaluates to true *)
val make_owned_if : int -> t
val join : t -> t -> t
end end
(** snapshot of the relevant state at the time of a heap access: concurrent thread(s), lock(s) held,
ownership precondition *)
module AccessSnapshot : sig
type t = private type t = private
{ access: TraceElem.t { access: TraceElem.t
; thread: ThreadsDomain.t ; thread: ThreadsDomain.t
; lock: bool ; lock: bool
; ownership_precondition: OwnershipPrecondition.t } ; ownership_precondition: OwnershipAbstractValue.t }
include PrettyPrintable.PrintableOrderedType with type t := t include PrettyPrintable.PrintableOrderedType with type t := t
@ -112,7 +115,7 @@ module AccessSnapshot : sig
-> TraceElem.t -> TraceElem.t
-> LocksDomain.t -> LocksDomain.t
-> ThreadsDomain.t -> ThreadsDomain.t
-> OwnershipPrecondition.t -> OwnershipAbstractValue.t
-> t option -> t option
val make_from_snapshot : FormalMap.t -> TraceElem.t -> t -> t option val make_from_snapshot : FormalMap.t -> TraceElem.t -> t -> t option
@ -129,19 +132,6 @@ module AccessDomain : sig
val add_opt : elt option -> t -> t val add_opt : elt option -> t -> t
end end
module OwnershipAbstractValue : sig
type t = private
| OwnedIf of IntSet.t
(** Owned if the formals at the given indexes are owned in the caller; unconditionally owned
if the set of formals is empty = bottom of the lattice *)
| Unowned (** Unowned value; top of the lattice *)
[@@deriving compare]
val owned : t
val make_owned_if : int -> t
end
module OwnershipDomain : sig module OwnershipDomain : sig
type t type t
@ -155,7 +145,7 @@ module OwnershipDomain : sig
val propagate_return : AccessExpression.t -> OwnershipAbstractValue.t -> HilExp.t list -> t -> t val propagate_return : AccessExpression.t -> OwnershipAbstractValue.t -> HilExp.t list -> t -> t
val get_precondition : AccessExpression.t -> t -> AccessSnapshot.OwnershipPrecondition.t val ownership_of_expr : HilExp.t -> t -> OwnershipAbstractValue.t
end end
module Attribute : sig module Attribute : sig

Loading…
Cancel
Save