[racerd] reduce attributes to a singleton

Summary: The attribute types present are exclusive, so sets are not needed for the attribute map domain.  This changes `Attribute` to a flat domain and removes the set on top of that.

Reviewed By: jberdine

Differential Revision: D20560240

fbshipit-source-id: 83e59d73e
master
Nikos Gorogiannis 5 years ago committed by Facebook GitHub Bot
parent 7937615a20
commit e3da644776

@ -196,7 +196,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
then then
(* TODO: check for constants, which are functional? *) (* TODO: check for constants, which are functional? *)
let attribute_map = let attribute_map =
AttributeMapDomain.add_attribute (AccessExpression.base ret_base) Functional AttributeMapDomain.add (AccessExpression.base ret_base) Functional
astate.attribute_map astate.attribute_map
in in
{astate with attribute_map} {astate with attribute_map}
@ -269,8 +269,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
{astate with threads= ThreadsDomain.AnyThreadButSelf} {astate with threads= ThreadsDomain.AnyThreadButSelf}
| MainThreadIfTrue -> | MainThreadIfTrue ->
let attribute_map = let attribute_map =
AttributeMapDomain.add_attribute ret_access_exp Attribute.OnMainThread AttributeMapDomain.add ret_access_exp Attribute.OnMainThread astate.attribute_map
astate.attribute_map
in in
{astate with attribute_map} {astate with attribute_map}
| UnknownThread -> | UnknownThread ->
@ -301,8 +300,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
; threads= update_for_lock_use astate.threads } ; threads= update_for_lock_use astate.threads }
| LockedIfTrue _ | GuardLockedIfTrue _ -> | LockedIfTrue _ | GuardLockedIfTrue _ ->
let attribute_map = let attribute_map =
AttributeMapDomain.add_attribute ret_access_exp Attribute.LockHeld AttributeMapDomain.add ret_access_exp Attribute.LockHeld astate.attribute_map
astate.attribute_map
in in
{astate with attribute_map; threads= update_for_lock_use astate.threads} {astate with attribute_map; threads= update_for_lock_use astate.threads}
| GuardConstruct {acquire_now= false} -> | GuardConstruct {acquire_now= false} ->
@ -318,7 +316,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
{summary with accesses= rebased_accesses} ) {summary with accesses= rebased_accesses} )
in in
match rebased_summary_opt with match rebased_summary_opt with
| Some {threads; locks; accesses; return_ownership; return_attributes} -> | Some {threads; locks; accesses; return_ownership; return_attribute} ->
let locks = let locks =
LocksDomain.integrate_summary ~caller_astate:astate.locks ~callee_astate:locks LocksDomain.integrate_summary ~caller_astate:astate.locks ~callee_astate:locks
in in
@ -330,7 +328,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
astate.ownership astate.ownership
in in
let attribute_map = let attribute_map =
AttributeMapDomain.add ret_access_exp return_attributes astate.attribute_map AttributeMapDomain.add ret_access_exp return_attribute astate.attribute_map
in in
let threads = let threads =
ThreadsDomain.integrate_summary ~caller_astate:astate.threads ThreadsDomain.integrate_summary ~caller_astate:astate.threads
@ -342,7 +340,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
in in
let add_if_annotated predicate attribute attribute_map = let add_if_annotated predicate attribute attribute_map =
if PatternMatch.override_exists predicate tenv callee_pname then if PatternMatch.override_exists predicate tenv callee_pname then
AttributeMapDomain.add_attribute ret_access_exp attribute attribute_map AttributeMapDomain.add ret_access_exp attribute attribute_map
else attribute_map else attribute_map
in in
let attribute_map = add_if_annotated is_functional Functional astate_callee.attribute_map in let attribute_map = add_if_annotated is_functional Functional astate_callee.attribute_map in
@ -409,7 +407,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
if bool_value then ThreadsDomain.AnyThreadButSelf else ThreadsDomain.AnyThread if bool_value then ThreadsDomain.AnyThreadButSelf else ThreadsDomain.AnyThread
in in
{acc with threads} {acc with threads}
| Attribute.Functional -> | Attribute.(Functional | Nothing) ->
acc acc
in in
let accesses = let accesses =
@ -420,11 +418,11 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
match HilExp.get_access_exprs assume_exp with match HilExp.get_access_exprs assume_exp with
| [access_expr] -> | [access_expr] ->
HilExp.eval_boolean_exp access_expr assume_exp HilExp.eval_boolean_exp access_expr assume_exp
|> Option.fold ~init:astate ~f:(fun init bool_value -> |> Option.value_map ~default:astate ~f:(fun bool_value ->
let choices = AttributeMapDomain.get_choices access_expr astate.attribute_map in
(* prune (prune_exp) can only evaluate to true if the choice is [bool_value]. (* prune (prune_exp) can only evaluate to true if the choice is [bool_value].
add the constraint that the choice must be [bool_value] to the state *) add the constraint that the choice must be [bool_value] to the state *)
List.fold ~f:(apply_choice bool_value) ~init choices ) AttributeMapDomain.find access_expr astate.attribute_map
|> apply_choice bool_value astate )
| _ -> | _ ->
astate astate
in in
@ -548,15 +546,12 @@ let analyze_procedure {Callbacks.exe_env; summary} =
(Var.of_pvar (Pvar.get_ret_pvar proc_name), Procdesc.get_ret_type proc_desc) (Var.of_pvar (Pvar.get_ret_pvar proc_name), Procdesc.get_ret_type proc_desc)
in in
let return_ownership = OwnershipDomain.get_owned return_var_exp ownership in let return_ownership = OwnershipDomain.get_owned return_var_exp ownership in
let return_attributes = let return_attribute = AttributeMapDomain.find return_var_exp attribute_map in
try AttributeMapDomain.find return_var_exp attribute_map
with Caml.Not_found -> AttributeSetDomain.empty
in
let locks = let locks =
(* if method is [synchronized] released the lock once. *) (* if method is [synchronized] released the lock once. *)
if Procdesc.is_java_synchronized proc_desc then LocksDomain.release_lock locks else locks if Procdesc.is_java_synchronized proc_desc then LocksDomain.release_lock locks else locks
in in
let post = {threads; locks; accesses; return_ownership; return_attributes} in let post = {threads; locks; accesses; return_ownership; return_attribute} in
Payload.update_summary post summary Payload.update_summary post summary
| None -> | None ->
summary summary

@ -439,71 +439,62 @@ module OwnershipDomain = struct
end end
module Attribute = struct module Attribute = struct
type t = Functional | OnMainThread | LockHeld [@@deriving compare] type t = Nothing | Functional | OnMainThread | LockHeld [@@deriving equal]
let pp fmt = function let pp fmt t =
( match t with
| Nothing ->
"Nothing"
| Functional -> | Functional ->
F.pp_print_string fmt "Functional" "Functional"
| OnMainThread -> | OnMainThread ->
F.pp_print_string fmt "OnMainThread" "OnMainThread"
| LockHeld -> | LockHeld ->
F.pp_print_string fmt "LockHeld" "LockHeld" )
end |> F.pp_print_string fmt
module AttributeSetDomain = AbstractDomain.InvertedSet (Attribute)
module AttributeMapDomain = struct let top = Nothing
include AbstractDomain.InvertedMap (AccessExpression) (AttributeSetDomain)
let add access_expression attribute_set t = let is_top = function Nothing -> true | _ -> false
if AttributeSetDomain.is_empty attribute_set then t else add access_expression attribute_set t
let join t t' = if equal t t' then t else Nothing
let has_attribute access_expression attribute t = let leq ~lhs ~rhs = equal (join lhs rhs) rhs
find_opt access_expression t |> Option.exists ~f:(AttributeSetDomain.mem attribute)
let widen ~prev ~next ~num_iters:_ = join prev next
end
let get_choices access_expression t = module AttributeMapDomain = struct
match find_opt access_expression t with include AbstractDomain.SafeInvertedMap (AccessExpression) (Attribute)
| None ->
[]
| Some attributes ->
AttributeSetDomain.fold
(fun cc acc -> match cc with OnMainThread | LockHeld -> cc :: acc | _ -> acc)
attributes []
let find acc_exp t = find_opt acc_exp t |> Option.value ~default:Attribute.top
let add_attribute access_expression attribute t = let has_attribute access_expression attribute t =
update access_expression find_opt access_expression t |> Option.exists ~f:(Attribute.equal attribute)
(function
| Some attrs ->
Some (AttributeSetDomain.add attribute attrs)
| None ->
Some (AttributeSetDomain.singleton attribute) )
t
let rec attributes_of_expr attribute_map (e : HilExp.t) = let rec attribute_of_expr attribute_map (e : HilExp.t) =
match e with match e with
| AccessExpression access_expr -> | AccessExpression access_expr ->
find_opt access_expr attribute_map |> Option.value ~default:AttributeSetDomain.empty find access_expr attribute_map
| Constant _ -> | Constant _ ->
AttributeSetDomain.singleton Attribute.Functional Attribute.Functional
| Exception expr (* treat exceptions as transparent wrt attributes *) | Cast (_, expr) -> | Exception expr (* treat exceptions as transparent wrt attributes *) | Cast (_, expr) ->
attributes_of_expr attribute_map expr attribute_of_expr attribute_map expr
| UnaryOperator (_, expr, _) -> | UnaryOperator (_, expr, _) ->
attributes_of_expr attribute_map expr attribute_of_expr attribute_map expr
| BinaryOperator (_, expr1, expr2) -> | BinaryOperator (_, expr1, expr2) ->
let attributes1 = attributes_of_expr attribute_map expr1 in let attribute1 = attribute_of_expr attribute_map expr1 in
let attributes2 = attributes_of_expr attribute_map expr2 in let attribute2 = attribute_of_expr attribute_map expr2 in
AttributeSetDomain.join attributes1 attributes2 Attribute.join attribute1 attribute2
| Closure _ | Sizeof _ -> | Closure _ | Sizeof _ ->
AttributeSetDomain.empty Attribute.top
let propagate_assignment lhs_access_expression rhs_exp attribute_map = let propagate_assignment lhs_access_expression rhs_exp attribute_map =
let rhs_attributes = attributes_of_expr attribute_map rhs_exp in let rhs_attribute = attribute_of_expr attribute_map rhs_exp in
add lhs_access_expression rhs_attributes attribute_map add lhs_access_expression rhs_attribute attribute_map
end end
type t = type t =
@ -566,21 +557,21 @@ type summary =
; locks: LocksDomain.t ; locks: LocksDomain.t
; accesses: AccessDomain.t ; accesses: AccessDomain.t
; return_ownership: OwnershipAbstractValue.t ; return_ownership: OwnershipAbstractValue.t
; return_attributes: AttributeSetDomain.t } ; return_attribute: Attribute.t }
let empty_summary = let empty_summary =
{ threads= ThreadsDomain.bottom { threads= ThreadsDomain.bottom
; locks= LocksDomain.empty ; locks= LocksDomain.empty
; accesses= AccessDomain.empty ; accesses= AccessDomain.empty
; return_ownership= OwnershipAbstractValue.unowned ; return_ownership= OwnershipAbstractValue.unowned
; return_attributes= AttributeSetDomain.empty } ; return_attribute= Attribute.top }
let pp_summary fmt {threads; locks; accesses; return_ownership; return_attributes} = let pp_summary fmt {threads; locks; accesses; return_ownership; return_attribute} =
F.fprintf fmt F.fprintf fmt
"@\nThreads: %a, Locks: %a @\nAccesses %a @\nOwnership: %a @\nReturn Attributes: %a @\n" "@\nThreads: %a, Locks: %a @\nAccesses %a @\nOwnership: %a @\nReturn Attributes: %a @\n"
ThreadsDomain.pp threads LocksDomain.pp locks AccessDomain.pp accesses OwnershipAbstractValue.pp ThreadsDomain.pp threads LocksDomain.pp locks AccessDomain.pp accesses OwnershipAbstractValue.pp
return_ownership AttributeSetDomain.pp return_attributes return_ownership Attribute.pp return_attribute
let pp fmt {threads; locks; accesses; ownership; attribute_map} = let pp fmt {threads; locks; accesses; ownership; attribute_map} =

@ -160,33 +160,21 @@ end
module Attribute : sig module Attribute : sig
type t = type t =
| Nothing
| Functional (** holds a value returned from a callee marked [@Functional] *) | Functional (** holds a value returned from a callee marked [@Functional] *)
| OnMainThread (** boolean is true if the current procedure is running on the main thread *) | OnMainThread (** boolean is true if the current procedure is running on the main thread *)
| LockHeld (** boolean is true if a lock is currently held *) | LockHeld (** boolean is true if a lock is currently held *)
include PrettyPrintable.PrintableOrderedType with type t := t
end
module AttributeSetDomain : sig
type t
val empty : t
end end
module AttributeMapDomain : sig module AttributeMapDomain : sig
type t type t
val find : AccessExpression.t -> t -> AttributeSetDomain.t val find : AccessExpression.t -> t -> Attribute.t
val add : AccessExpression.t -> AttributeSetDomain.t -> t -> t val add : AccessExpression.t -> Attribute.t -> t -> t
val has_attribute : AccessExpression.t -> Attribute.t -> t -> bool val has_attribute : AccessExpression.t -> Attribute.t -> t -> bool
val get_choices : AccessExpression.t -> t -> Attribute.t list
(** get the choice attributes associated with the given access path *)
val add_attribute : AccessExpression.t -> Attribute.t -> t -> t
val propagate_assignment : AccessExpression.t -> HilExp.t -> t -> t val propagate_assignment : AccessExpression.t -> HilExp.t -> t -> t
(** propagate attributes from the leaves to the root of an RHS Hil expression *) (** propagate attributes from the leaves to the root of an RHS Hil expression *)
end end
@ -208,7 +196,7 @@ type summary =
; locks: LocksDomain.t ; locks: LocksDomain.t
; accesses: AccessDomain.t ; accesses: AccessDomain.t
; return_ownership: OwnershipAbstractValue.t ; return_ownership: OwnershipAbstractValue.t
; return_attributes: AttributeSetDomain.t } ; return_attribute: Attribute.t }
val empty_summary : summary val empty_summary : summary

Loading…
Cancel
Save