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
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
|