(* * Copyright (c) 2016 - present Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. *) open! IStd module F = Format module AccessPathSetDomain = AbstractDomain.InvertedSet(AccessPath.RawSet) module TraceElem = struct module Kind = AccessPath.Raw type t = { site : CallSite.t; kind : Kind.t; } [@@deriving compare] let call_site { site; } = site let kind { kind; } = kind let make kind site = { kind; site; } let with_callsite t site = { t with site; } let pp fmt { site; kind; } = F.fprintf fmt "Unprotected access to %a at %a" Kind.pp kind CallSite.pp site module Set = PrettyPrintable.MakePPSet (struct type nonrec t = t let compare = compare let pp = pp end) end let make_access kind loc = let site = CallSite.make Procname.empty_block loc in TraceElem.make kind site module LocksDomain = AbstractDomain.BooleanAnd module PathDomain = SinkTrace.Make(TraceElem) module IntMap = PrettyPrintable.MakePPMap(Int) module ConditionalWritesDomain = AbstractDomain.Map (IntMap) (PathDomain) module Attribute = struct type t = | OwnedIf of int option | Functional [@@deriving compare] let pp fmt = function | OwnedIf None -> F.fprintf fmt "Owned" | OwnedIf (Some formal_index) -> F.fprintf fmt "Owned if formal %d is owned" formal_index | Functional -> F.fprintf fmt "Functional" let unconditionally_owned = OwnedIf None module Set = PrettyPrintable.MakePPSet(struct type nonrec t = t let compare = compare let pp = pp end) end module AttributeSetDomain = AbstractDomain.InvertedSet (Attribute.Set) module AttributeMapDomain = struct include AbstractDomain.InvertedMap (AccessPath.RawMap) (AttributeSetDomain) let has_attribute access_path attribute t = try find access_path t |> AttributeSetDomain.mem attribute with Not_found -> false let add_attribute access_path attribute t = let attribute_set = (try find access_path t with Not_found -> AttributeSetDomain.empty) |> AttributeSetDomain.add attribute in add access_path attribute_set t end type astate = { locks : LocksDomain.astate; reads : PathDomain.astate; conditional_writes : ConditionalWritesDomain.astate; unconditional_writes : PathDomain.astate; id_map : IdAccessPathMapDomain.astate; attribute_map : AttributeMapDomain.astate; } type summary = LocksDomain.astate * PathDomain.astate * ConditionalWritesDomain.astate * PathDomain.astate * AttributeSetDomain.astate let empty = let locks = false in let reads = PathDomain.empty in let conditional_writes = ConditionalWritesDomain.empty in let unconditional_writes = PathDomain.empty in let id_map = IdAccessPathMapDomain.empty in let attribute_map = AccessPath.RawMap.empty in { locks; reads; conditional_writes; unconditional_writes; id_map; attribute_map; } let (<=) ~lhs ~rhs = if phys_equal lhs rhs then true else LocksDomain.(<=) ~lhs:lhs.locks ~rhs:rhs.locks && PathDomain.(<=) ~lhs:lhs.reads ~rhs:rhs.reads && ConditionalWritesDomain.(<=) ~lhs:lhs.conditional_writes ~rhs:rhs.conditional_writes && PathDomain.(<=) ~lhs:lhs.unconditional_writes ~rhs:rhs.unconditional_writes && IdAccessPathMapDomain.(<=) ~lhs:lhs.id_map ~rhs:rhs.id_map && AttributeMapDomain.(<=) ~lhs:lhs.attribute_map ~rhs:rhs.attribute_map let join astate1 astate2 = if phys_equal astate1 astate2 then astate1 else let locks = LocksDomain.join astate1.locks astate2.locks in let reads = PathDomain.join astate1.reads astate2.reads in let conditional_writes = ConditionalWritesDomain.join astate1.conditional_writes astate2.conditional_writes in let unconditional_writes = PathDomain.join astate1.unconditional_writes astate2.unconditional_writes in let id_map = IdAccessPathMapDomain.join astate1.id_map astate2.id_map in let attribute_map = AttributeMapDomain.join astate1.attribute_map astate2.attribute_map in { locks; reads; conditional_writes; unconditional_writes; id_map; attribute_map; } let widen ~prev ~next ~num_iters = if phys_equal prev next then prev else let locks = LocksDomain.widen ~prev:prev.locks ~next:next.locks ~num_iters in let reads = PathDomain.widen ~prev:prev.reads ~next:next.reads ~num_iters in let conditional_writes = ConditionalWritesDomain.widen ~prev:prev.conditional_writes ~next:next.conditional_writes ~num_iters in let unconditional_writes = PathDomain.widen ~prev:prev.unconditional_writes ~next:next.unconditional_writes ~num_iters in let id_map = IdAccessPathMapDomain.widen ~prev:prev.id_map ~next:next.id_map ~num_iters in let attribute_map = AttributeMapDomain.widen ~prev:prev.attribute_map ~next:next.attribute_map ~num_iters in { locks; reads; conditional_writes; unconditional_writes; id_map; attribute_map; } let pp_summary fmt (locks, reads, conditional_writes, unconditional_writes, return_attributes) = F.fprintf fmt "Locks: %a Reads: %a Conditional Writes: %a Unconditional Writes: %a Return Attributes: %a" LocksDomain.pp locks PathDomain.pp reads ConditionalWritesDomain.pp conditional_writes PathDomain.pp unconditional_writes AttributeSetDomain.pp return_attributes let pp fmt { locks; reads; conditional_writes; unconditional_writes; id_map; attribute_map; } = F.fprintf fmt "Locks: %a Reads: %a Conditional Writes: %a Unconditional Writes: %a Id Map: %a Attribute Map:\ %a" LocksDomain.pp locks PathDomain.pp reads ConditionalWritesDomain.pp conditional_writes PathDomain.pp unconditional_writes IdAccessPathMapDomain.pp id_map AttributeMapDomain.pp attribute_map