You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

153 lines
4.9 KiB

(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open! IStd
module F = Format
(** Domain for thread-type. The main goals are
- Track code paths that are explicitly on UI thread (via annotations, or assertions).
- Maintain UI-thread-ness through the call stack (if a callee is on UI thread then the
trace any call site must be on the UI thread too).
- If we are not on the UI thread we assume we are on a background thread.
- Traces with "UI-thread" status cannot interleave but all other combinations can.
- We do not track other annotations (eg WorkerThread or AnyThread) as they can be
erroneously applied -- other checkers should catch those errors (annotation reachability).
- Top is AnyThread, and is used as the initial state for analysis.
*)
module ThreadDomain : sig
type t = UIThread | AnyThread
include AbstractDomain.WithTop with type t := t
end
(** Abstraction of a path that represents a lock, special-casing comparison
to work over type, base variable modulo this and access list *)
module Lock : sig
include PrettyPrintable.PrintableOrderedType with type t = AccessPath.t
val owner_class : t -> Typ.name option
(** Class of the root variable of the path representing the lock *)
val pp_locks : F.formatter -> t -> unit
val describe : F.formatter -> t -> unit
end
module Event : sig
type t =
| LockAcquire of Lock.t
| MayBlock of (string * StarvationModels.severity)
| StrictModeCall of string
[@@deriving compare]
val describe : F.formatter -> t -> unit
end
module LockState : AbstractDomain.WithTop
(** A set of lock acquisitions with source locations and procnames. *)
module Acquisitions : sig
type t
val lock_is_held : Lock.t -> t -> bool
(** is the given lock in the set *)
end
(** An event and the currently-held locks at the time it occurred. *)
module CriticalPairElement : sig
type t = private {acquisitions: Acquisitions.t; event: Event.t; thread: ThreadDomain.t}
end
(** A [CriticalPairElement] equipped with a call stack.
The intuition is that if we have a critical pair `(locks, event)` in the summary
of a method then there is a trace of that method where `event` occurs, and right
before it occurs the locks held are exactly `locks` (no over/under approximation).
We call it "critical" because the information here alone determines deadlock conditions.
*)
module CriticalPair : sig
type t = private {elem: CriticalPairElement.t; loc: Location.t; trace: CallSite.t list}
include PrettyPrintable.PrintableOrderedType with type t := t
val get_loc : t -> Location.t
(** outermost callsite location *)
val get_earliest_lock_or_call_loc : procname:Typ.Procname.t -> t -> Location.t
(** outermost callsite location OR lock acquisition *)
val may_deadlock : t -> t -> bool
(** two pairs can run in parallel and satisfy the conditions for deadlock *)
val make_trace :
?header:string -> ?include_acquisitions:bool -> Typ.Procname.t -> t -> Errlog.loc_trace
val is_uithread : t -> bool
(** is pair about an event on the UI thread *)
val can_run_in_parallel : t -> t -> bool
(** can two pairs describe events on two threads that can run in parallel *)
end
module CriticalPairs : AbstractDomain.FiniteSetS with type elt = CriticalPair.t
module GuardToLockMap : AbstractDomain.WithTop
type t =
{ guard_map: GuardToLockMap.t
; lock_state: LockState.t
; critical_pairs: CriticalPairs.t
; thread: ThreadDomain.t }
include AbstractDomain.WithBottom with type t := t
val acquire : Tenv.t -> t -> procname:Typ.Procname.t -> loc:Location.t -> Lock.t list -> t
(** simultaneously acquire a number of locks, no-op if list is empty *)
val release : t -> Lock.t list -> t
(** simultaneously release a number of locks, no-op if list is empty *)
val blocking_call : callee:Typ.Procname.t -> StarvationModels.severity -> loc:Location.t -> t -> t
val strict_mode_call : callee:Typ.Procname.t -> loc:Location.t -> t -> t
val set_on_ui_thread : t -> t
(** signal that the procedure is running on UI thread *)
val add_guard :
acquire_now:bool
-> procname:Typ.Procname.t
-> loc:Location.t
-> Tenv.t
-> t
-> HilExp.t
-> Lock.t
-> t
(** Install a mapping from the guard expression to the lock provided, and optionally lock it. *)
val lock_guard : procname:Typ.Procname.t -> loc:Location.t -> Tenv.t -> t -> HilExp.t -> t
(** Acquire the lock the guard was constructed with. *)
val remove_guard : t -> HilExp.t -> t
(** Destroy the guard and release its lock. *)
val unlock_guard : t -> HilExp.t -> t
(** Release the lock the guard was constructed with. *)
type summary = t
val pp_summary : F.formatter -> summary -> unit
val integrate_summary :
Tenv.t
-> caller_summary:t
-> callee:Typ.Procname.t
-> loc:Location.t
-> callee_summary:summary
-> t
val filter_blocking_calls : t -> t