diff --git a/infer/src/backend/StarvationGlobalAnalysis.ml b/infer/src/backend/StarvationGlobalAnalysis.ml index 8f71cd776..b9a3b6193 100644 --- a/infer/src/backend/StarvationGlobalAnalysis.ml +++ b/infer/src/backend/StarvationGlobalAnalysis.ml @@ -75,7 +75,7 @@ let report exe_env work_set = tenv pattrs pair acc in match pair.elem.event with - | LockAcquire locks -> + | LockAcquire {locks} -> List.fold locks ~init:acc ~f:(fun acc lock -> let should_report_starvation = CriticalPair.is_uithread pair && not (Procname.is_constructor procname) diff --git a/infer/src/concurrency/starvation.ml b/infer/src/concurrency/starvation.ml index 365fb3fb9..16453a181 100644 --- a/infer/src/concurrency/starvation.ml +++ b/infer/src/concurrency/starvation.ml @@ -605,7 +605,7 @@ let should_report_deadlock_on_current_proc current_elem endpoint_elem = (* should never happen *) L.die InternalError "Deadlock cannot occur without two lock events: %a" CriticalPair.pp current_elem - | LockAcquire endpoint_locks, LockAcquire current_locks -> ( + | LockAcquire {locks= endpoint_locks}, LockAcquire {locks= current_locks} -> ( (* first elem is a class object (see [lock_of_class]), so always report because the reverse ordering on the events will not occur since we don't search the class for static locks *) List.exists ~f:Lock.is_class_object endpoint_locks @@ -671,7 +671,7 @@ let report_on_parallel_composition ~should_report_starvation tenv pattrs pair lo if CriticalPair.can_run_in_parallel pair other_pair then let acquisitions = other_pair.CriticalPair.elem.acquisitions in match other_pair.CriticalPair.elem.event with - | MayBlock (_, sev) as event + | MayBlock {severity} as event when should_report_starvation && Acquisitions.lock_is_held_in_other_thread tenv lock acquisitions -> let error_message = @@ -680,8 +680,8 @@ let report_on_parallel_composition ~should_report_starvation tenv pattrs pair lo pname_pp pname Lock.pp_locks lock Event.describe event in let ltr, loc = make_trace_and_loc () in - ReportMap.add_starvation sev tenv pattrs loc ltr error_message report_map - | MonitorWait monitor_lock + ReportMap.add_starvation severity tenv pattrs loc ltr error_message report_map + | MonitorWait {lock= monitor_lock} when should_report_starvation && Acquisitions.lock_is_held_in_other_thread tenv lock acquisitions && not (Lock.equal lock monitor_lock) -> @@ -723,13 +723,13 @@ let report_on_pair ~analyze_ondemand tenv pattrs (pair : Domain.CriticalPair.t) (ltr, loc) in match event with - | MayBlock (_, sev) when should_report_starvation -> + | MayBlock {severity} when should_report_starvation -> let error_message = Format.asprintf "Method %a runs on UI thread and may block; %a." pname_pp pname Event.describe event in let ltr, loc = make_trace_and_loc () in - ReportMap.add_starvation sev tenv pattrs loc ltr error_message report_map + ReportMap.add_starvation severity tenv pattrs loc ltr error_message report_map | MonitorWait _ when should_report_starvation -> let error_message = Format.asprintf "Method %a runs on UI thread and may block; %a." pname_pp pname @@ -753,7 +753,7 @@ let report_on_pair ~analyze_ondemand tenv pattrs (pair : Domain.CriticalPair.t) let loc = CriticalPair.get_earliest_lock_or_call_loc ~procname:pname pair in let ltr = CriticalPair.make_trace pname pair in ReportMap.add_lockless_violation tenv pattrs loc ltr error_message report_map - | LockAcquire locks -> ( + | LockAcquire {locks} -> ( match List.find locks ~f:(fun lock -> Acquisitions.lock_is_held lock pair.elem.acquisitions) with diff --git a/infer/src/concurrency/starvationDomain.ml b/infer/src/concurrency/starvationDomain.ml index af53f651e..dbe187d78 100644 --- a/infer/src/concurrency/starvationDomain.ml +++ b/infer/src/concurrency/starvationDomain.ml @@ -177,56 +177,61 @@ end module Event = struct type t = - | LockAcquire of Lock.t list - | MayBlock of (Procname.t * StarvationModels.severity) - | StrictModeCall of Procname.t - | MonitorWait of Lock.t + | LockAcquire of {locks: Lock.t list} + | MayBlock of {callee: Procname.t; severity: StarvationModels.severity} + | StrictModeCall of {callee: Procname.t} + | MonitorWait of {lock: Lock.t} [@@deriving compare] let pp fmt = function - | LockAcquire locks -> + | LockAcquire {locks} -> F.fprintf fmt "LockAcquire(%a)" (PrettyPrintable.pp_collection ~pp_item:Lock.pp) locks - | MayBlock (pname, sev) -> - F.fprintf fmt "MayBlock(%a, %a)" Procname.pp pname StarvationModels.pp_severity sev - | StrictModeCall pname -> - F.fprintf fmt "StrictModeCall(%a)" Procname.pp pname - | MonitorWait lock -> + | MayBlock {callee; severity} -> + F.fprintf fmt "MayBlock(%a, %a)" Procname.pp callee StarvationModels.pp_severity severity + | StrictModeCall {callee} -> + F.fprintf fmt "StrictModeCall(%a)" Procname.pp callee + | MonitorWait {lock} -> F.fprintf fmt "MonitorWait(%a)" Lock.pp lock let describe fmt elem = match elem with - | LockAcquire locks -> + | LockAcquire {locks} -> Pp.comma_seq Lock.pp_locks fmt locks - | MayBlock (pname, _) | StrictModeCall pname -> - F.fprintf fmt "calls %a" describe_pname pname - | MonitorWait lock -> + | MayBlock {callee} | StrictModeCall {callee} -> + F.fprintf fmt "calls %a" describe_pname callee + | MonitorWait {lock} -> F.fprintf fmt "calls `wait` on %a" Lock.describe lock - let make_acquire lock = LockAcquire lock + let make_acquire locks = LockAcquire {locks} - let make_blocking_call callee sev = MayBlock (callee, sev) + let make_blocking_call callee severity = MayBlock {callee; severity} - let make_strict_mode_call callee = StrictModeCall callee + let make_strict_mode_call callee = StrictModeCall {callee} - let make_object_wait lock = MonitorWait lock + let make_object_wait lock = MonitorWait {lock} let apply_subst subst event = match event with | MayBlock _ | StrictModeCall _ -> Some event - | MonitorWait lock -> - Lock.apply_subst subst lock - |> Option.map ~f:(fun lock' -> if phys_equal lock lock' then event else MonitorWait lock') - | LockAcquire locks -> ( + | MonitorWait {lock} -> ( + match Lock.apply_subst subst lock with + | None -> + None + | Some lock' when phys_equal lock lock' -> + Some event + | Some lock -> + Some (MonitorWait {lock}) ) + | LockAcquire {locks} -> ( match Lock.apply_subst_to_list subst locks with | [] -> None | locks' when phys_equal locks locks' -> Some event - | locks' -> - Some (LockAcquire locks') ) + | locks -> + Some (LockAcquire {locks}) ) end (** A lock acquisition with source location and procname in which it occurs. The location & procname @@ -404,7 +409,7 @@ let is_recursive_lock event tenv = true in match (event : Event.t) with - | LockAcquire locks -> + | LockAcquire {locks} -> List.exists locks ~f:(fun lock_path -> Lock.get_typ tenv lock_path |> Option.exists ~f:is_class_and_recursive_lock ) | _ -> @@ -420,7 +425,7 @@ module CriticalPair = struct let may_deadlock tenv ~(lhs : t) ~lhs_lock ~(rhs : t) = let get_acquired_locks {elem= {event}} = - match event with LockAcquire locks -> locks | _ -> [] + match event with LockAcquire {locks} -> locks | _ -> [] in if ThreadDomain.can_run_in_parallel lhs.elem.thread rhs.elem.thread then get_acquired_locks rhs @@ -445,7 +450,7 @@ module CriticalPair = struct [held_locks] *) let filter_out_reentrant_relocks tenv_opt held_locks pair = match (tenv_opt, pair.elem.event) with - | Some tenv, LockAcquire locks -> ( + | Some tenv, LockAcquire {locks} -> ( let filtered_locks = IList.filter_changed locks ~f:(fun lock -> (not (Acquisitions.lock_is_held lock held_locks)) @@ -456,8 +461,8 @@ module CriticalPair = struct None | _ when phys_equal filtered_locks locks -> Some pair - | _ -> - Some (map pair ~f:(fun elem -> {elem with event= LockAcquire filtered_locks})) ) + | locks -> + Some (map pair ~f:(fun elem -> {elem with event= LockAcquire {locks}})) ) | _, _ -> Some pair diff --git a/infer/src/concurrency/starvationDomain.mli b/infer/src/concurrency/starvationDomain.mli index 3682f22cd..c75bdd9f9 100644 --- a/infer/src/concurrency/starvationDomain.mli +++ b/infer/src/concurrency/starvationDomain.mli @@ -57,10 +57,10 @@ end module Event : sig type t = - | LockAcquire of Lock.t list - | MayBlock of (Procname.t * StarvationModels.severity) - | StrictModeCall of Procname.t - | MonitorWait of Lock.t + | LockAcquire of {locks: Lock.t list} + | MayBlock of {callee: Procname.t; severity: StarvationModels.severity} + | StrictModeCall of {callee: Procname.t} + | MonitorWait of {lock: Lock.t} [@@deriving compare] val describe : F.formatter -> t -> unit