diff --git a/infer/src/IR/AccessPath.mli b/infer/src/IR/AccessPath.mli index 3b0bd76b3..bd0510156 100644 --- a/infer/src/IR/AccessPath.mli +++ b/infer/src/IR/AccessPath.mli @@ -24,6 +24,9 @@ val truncate : t -> t * access option (** remove and return the last access of the access path if the access list is non-empty. returns the original access path * None if the access list is empty *) +val get_access_type : Tenv.t -> Typ.t -> access -> Typ.t option +(** Get the type of an access, or None if the type cannot be determined *) + val get_last_access : t -> access option (** get the last access in the list. returns None if the list is empty *) @@ -66,6 +69,7 @@ val is_prefix : t -> t -> bool val replace_prefix : prefix:t -> t -> t -> t option [@@warning "-32"] val inner_class_normalize : t -> t + [@@warning "-32"] (** transform an access path that starts on "this" of an inner class but which breaks out to access outer class fields to the outermost one. Cases handled (recursively): diff --git a/infer/src/concurrency/starvation.ml b/infer/src/concurrency/starvation.ml index cf8c5915b..9e834ecc5 100644 --- a/infer/src/concurrency/starvation.ml +++ b/infer/src/concurrency/starvation.ml @@ -622,8 +622,8 @@ let report_on_parallel_composition ~should_report_starvation tenv pdesc pair loc let acquisitions = other_pair.CriticalPair.elem.acquisitions in match other_pair.CriticalPair.elem.event with | MayBlock (_, sev) as event - when should_report_starvation && Acquisitions.lock_is_held_in_other_thread lock acquisitions - -> + when should_report_starvation + && Acquisitions.lock_is_held_in_other_thread tenv lock acquisitions -> let error_message = Format.asprintf "Method %a runs on UI thread and%a, which may be held by another thread which %a." @@ -633,7 +633,7 @@ let report_on_parallel_composition ~should_report_starvation tenv pdesc pair loc ReportMap.add_starvation sev tenv pdesc loc ltr error_message report_map | MonitorWait monitor_lock when should_report_starvation - && Acquisitions.lock_is_held_in_other_thread lock acquisitions + && Acquisitions.lock_is_held_in_other_thread tenv lock acquisitions && not (Lock.equal lock monitor_lock) -> let error_message = Format.asprintf @@ -643,7 +643,7 @@ let report_on_parallel_composition ~should_report_starvation tenv pdesc pair loc let ltr, loc = make_trace_and_loc () in ReportMap.add_starvation High tenv pdesc loc ltr error_message report_map | LockAcquire other_lock - when CriticalPair.may_deadlock pair other_pair + when CriticalPair.may_deadlock tenv pair other_pair && should_report_deadlock_on_current_proc pair other_pair -> let error_message = Format.asprintf diff --git a/infer/src/concurrency/starvationDomain.ml b/infer/src/concurrency/starvationDomain.ml index 8b8a42300..a788763d7 100644 --- a/infer/src/concurrency/starvationDomain.ml +++ b/infer/src/concurrency/starvationDomain.ml @@ -104,14 +104,28 @@ module Lock = struct type t = {root: root; path: path} [@@deriving compare, equal] - let equal_across_threads t1 t2 = + let rec norm_path tenv ((typ, (accesses : AccessPath.access list)) as path) = + match accesses with + | (FieldAccess fieldname as access) :: rest when Fieldname.is_java_outer_instance fieldname -> ( + match AccessPath.get_access_type tenv typ access with + | Some typ' -> + norm_path tenv (typ', rest) + | None -> + path ) + | _ -> + path + + + let equal_across_threads tenv t1 t2 = match (t1.root, t2.root) with | Global _, Global _ | Class _, Class _ -> (* globals and class objects must be identical across threads *) equal t1 t2 | Parameter _, Parameter _ -> + let ((_, typ1), accesses1), ((_, typ2), accesses2) = (t1.path, t2.path) in (* parameter position/names can be ignored across threads, if types and accesses are equal *) - equal_path t1.path t2.path + let path1, path2 = (norm_path tenv (typ1, accesses1), norm_path tenv (typ2, accesses2)) in + [%equal: Typ.t * AccessPath.access list] path1 path2 | _, _ -> false @@ -146,10 +160,9 @@ module Lock = struct | Var.ProgramVar pvar when Pvar.is_global pvar -> Some (make_global path (Pvar.get_name pvar)) | Var.ProgramVar _ -> - let norm_path = AccessPath.inner_class_normalize path in - FormalMap.get_formal_index (fst norm_path) formal_map + FormalMap.get_formal_index (fst path) formal_map (* ignores non-formals *) - |> Option.map ~f:(make_parameter norm_path) ) + |> Option.map ~f:(make_parameter path) ) | Constant (Cclass class_id) -> (* this is a synchronized/lock(CLASSNAME.class) construct *) let path = path_of_java_class class_id in @@ -276,12 +289,12 @@ module Acquisitions = struct (* use the fact that location/procname are ignored in comparisons *) let lock_is_held lock acquisitions = mem (Acquisition.make_dummy lock) acquisitions - let lock_is_held_in_other_thread lock acquisitions = - exists (fun acq -> Lock.equal_across_threads lock acq.lock) acquisitions + let lock_is_held_in_other_thread tenv lock acquisitions = + exists (fun acq -> Lock.equal_across_threads tenv lock acq.lock) acquisitions - let no_locks_common_across_threads acqs1 acqs2 = - for_all (fun acq1 -> not (lock_is_held_in_other_thread acq1.lock acqs2)) acqs1 + let no_locks_common_across_threads tenv acqs1 acqs2 = + for_all (fun acq1 -> not (lock_is_held_in_other_thread tenv acq1.lock acqs2)) acqs1 end module LockState : sig @@ -409,15 +422,15 @@ module CriticalPair = struct match event with LockAcquire lock -> Some lock | _ -> None - let may_deadlock ({elem= pair1} as t1 : t) ({elem= pair2} as t2 : t) = + let may_deadlock tenv ({elem= pair1} as t1 : t) ({elem= pair2} as t2 : t) = ThreadDomain.can_run_in_parallel pair1.thread pair2.thread && Option.both (get_final_acquire t1) (get_final_acquire t2) |> Option.exists ~f:(fun (lock1, lock2) -> - (not (Lock.equal_across_threads lock1 lock2)) - && Acquisitions.lock_is_held_in_other_thread lock2 pair1.acquisitions - && Acquisitions.lock_is_held_in_other_thread lock1 pair2.acquisitions - && Acquisitions.no_locks_common_across_threads pair1.acquisitions pair2.acquisitions - ) + (not (Lock.equal_across_threads tenv lock1 lock2)) + && Acquisitions.lock_is_held_in_other_thread tenv lock2 pair1.acquisitions + && Acquisitions.lock_is_held_in_other_thread tenv lock1 pair2.acquisitions + && Acquisitions.no_locks_common_across_threads tenv pair1.acquisitions + pair2.acquisitions ) let integrate_summary_opt existing_acquisitions call_site (caller_thread : ThreadDomain.t) diff --git a/infer/src/concurrency/starvationDomain.mli b/infer/src/concurrency/starvationDomain.mli index ee3602ccb..39834f262 100644 --- a/infer/src/concurrency/starvationDomain.mli +++ b/infer/src/concurrency/starvationDomain.mli @@ -87,7 +87,7 @@ module Acquisitions : sig val lock_is_held : Lock.t -> t -> bool (** is the given lock in the set *) - val lock_is_held_in_other_thread : Lock.t -> t -> bool + val lock_is_held_in_other_thread : Tenv.t -> Lock.t -> t -> bool (** is the given lock held, modulo memory abstraction across threads *) end @@ -112,7 +112,7 @@ module CriticalPair : sig val get_earliest_lock_or_call_loc : procname:Procname.t -> t -> Location.t (** outermost callsite location OR lock acquisition *) - val may_deadlock : t -> t -> bool + val may_deadlock : Tenv.t -> t -> t -> bool (** two pairs can run in parallel and satisfy the conditions for deadlock *) val make_trace : diff --git a/infer/tests/codetoanalyze/java/starvation-whole-program/issues.exp b/infer/tests/codetoanalyze/java/starvation-whole-program/issues.exp index c328b40ac..25635920e 100644 --- a/infer/tests/codetoanalyze/java/starvation-whole-program/issues.exp +++ b/infer/tests/codetoanalyze/java/starvation-whole-program/issues.exp @@ -3,18 +3,18 @@ codetoanalyze/java/starvation-whole-program/AttributeFlows.java, AttributeFlows. codetoanalyze/java/starvation-whole-program/AttributeFlows.java, AttributeFlows.postRunnableIndirectlyToUIThreadBad():void, 115, STARVATION, no_bucket, ERROR, [`void AttributeFlows.postRunnableIndirectlyToUIThreadBad()`,Method call: `void AttributeFlows$5.run()`,Method call: `void AttributeFlows.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] codetoanalyze/java/starvation-whole-program/ConstructedAttributes.java, ConstructedAttributes.postBlockingCallToUIExecutorBad():void, 52, STARVATION, no_bucket, ERROR, [`void ConstructedAttributes.postBlockingCallToUIExecutorBad()`,Method call: `void ConstructedAttributes$1.run()`,Method call: `void ConstructedAttributes.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] codetoanalyze/java/starvation-whole-program/ConstructedAttributes.java, ConstructedAttributes.postBlockingCallToUIHandlerBad():void, 64, STARVATION, no_bucket, ERROR, [`void ConstructedAttributes.postBlockingCallToUIHandlerBad()`,Method call: `void ConstructedAttributes$1.run()`,Method call: `void ConstructedAttributes.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] -codetoanalyze/java/starvation-whole-program/Deadlock.java, Deadlock.postDeadlockBad():void, 19, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void Deadlock.postDeadlockBad()`,Method call: `void Deadlock$1.run()`, locks `this.monitorA` in `class Deadlock`, locks `this.monitorB` in `class Deadlock`,[Trace 2] `void Deadlock.postDeadlockBad()`,Method call: `void Deadlock$2.run()`, locks `this.monitorB` in `class Deadlock`, locks `this.monitorA` in `class Deadlock`] -codetoanalyze/java/starvation-whole-program/Deadlock.java, Deadlock.postDeadlockBad():void, 30, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void Deadlock.postDeadlockBad()`,Method call: `void Deadlock$2.run()`, locks `this.monitorB` in `class Deadlock`, locks `this.monitorA` in `class Deadlock`,[Trace 2] `void Deadlock.postDeadlockBad()`,Method call: `void Deadlock$1.run()`, locks `this.monitorA` in `class Deadlock`, locks `this.monitorB` in `class Deadlock`] -codetoanalyze/java/starvation-whole-program/Deadlock.java, Deadlock.postOnBGThreadBad():void, 73, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void Deadlock.postOnBGThreadBad()`,Method call: `void Deadlock$5.run()`, locks `this.monitorE` in `class Deadlock`, locks `this.monitorF` in `class Deadlock`,[Trace 2] `void Deadlock.postOnBGThreadBad()`,Method call: `void Deadlock$6.run()`, locks `this.monitorF` in `class Deadlock`, locks `this.monitorE` in `class Deadlock`] -codetoanalyze/java/starvation-whole-program/Deadlock.java, Deadlock.postOnBGThreadBad():void, 84, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void Deadlock.postOnBGThreadBad()`,Method call: `void Deadlock$6.run()`, locks `this.monitorF` in `class Deadlock`, locks `this.monitorE` in `class Deadlock`,[Trace 2] `void Deadlock.postOnBGThreadBad()`,Method call: `void Deadlock$5.run()`, locks `this.monitorE` in `class Deadlock`, locks `this.monitorF` in `class Deadlock`] +codetoanalyze/java/starvation-whole-program/Deadlock.java, Deadlock.postDeadlockBad():void, 19, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void Deadlock.postDeadlockBad()`,Method call: `void Deadlock$1.run()`, locks `this.this$0.monitorA` in `class Deadlock$1`, locks `this.this$0.monitorB` in `class Deadlock$1`,[Trace 2] `void Deadlock.postDeadlockBad()`,Method call: `void Deadlock$2.run()`, locks `this.this$0.monitorB` in `class Deadlock$2`, locks `this.this$0.monitorA` in `class Deadlock$2`] +codetoanalyze/java/starvation-whole-program/Deadlock.java, Deadlock.postDeadlockBad():void, 30, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void Deadlock.postDeadlockBad()`,Method call: `void Deadlock$2.run()`, locks `this.this$0.monitorB` in `class Deadlock$2`, locks `this.this$0.monitorA` in `class Deadlock$2`,[Trace 2] `void Deadlock.postDeadlockBad()`,Method call: `void Deadlock$1.run()`, locks `this.this$0.monitorA` in `class Deadlock$1`, locks `this.this$0.monitorB` in `class Deadlock$1`] +codetoanalyze/java/starvation-whole-program/Deadlock.java, Deadlock.postOnBGThreadBad():void, 73, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void Deadlock.postOnBGThreadBad()`,Method call: `void Deadlock$5.run()`, locks `this.this$0.monitorE` in `class Deadlock$5`, locks `this.this$0.monitorF` in `class Deadlock$5`,[Trace 2] `void Deadlock.postOnBGThreadBad()`,Method call: `void Deadlock$6.run()`, locks `this.this$0.monitorF` in `class Deadlock$6`, locks `this.this$0.monitorE` in `class Deadlock$6`] +codetoanalyze/java/starvation-whole-program/Deadlock.java, Deadlock.postOnBGThreadBad():void, 84, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void Deadlock.postOnBGThreadBad()`,Method call: `void Deadlock$6.run()`, locks `this.this$0.monitorF` in `class Deadlock$6`, locks `this.this$0.monitorE` in `class Deadlock$6`,[Trace 2] `void Deadlock.postOnBGThreadBad()`,Method call: `void Deadlock$5.run()`, locks `this.this$0.monitorE` in `class Deadlock$5`, locks `this.this$0.monitorF` in `class Deadlock$5`] codetoanalyze/java/starvation-whole-program/DirectStarvation.java, DirectStarvation.postBlockingCallToUIThreadBad():void, 29, STARVATION, no_bucket, ERROR, [`void DirectStarvation.postBlockingCallToUIThreadBad()`,Method call: `void DirectStarvation$1.run()`,Method call: `void DirectStarvation.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] codetoanalyze/java/starvation-whole-program/ImplicitConstructor.java, ImplicitConstructor.postBlockingCallToUIExecutorBad():void, 54, STARVATION, no_bucket, ERROR, [`void ImplicitConstructor.postBlockingCallToUIExecutorBad()`,Method call: `void ImplicitConstructor$1.run()`,Method call: `void ImplicitConstructor.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] codetoanalyze/java/starvation-whole-program/ImplicitConstructor.java, ImplicitConstructor.postBlockingCallToUIHandlerBad():void, 66, STARVATION, no_bucket, ERROR, [`void ImplicitConstructor.postBlockingCallToUIHandlerBad()`,Method call: `void ImplicitConstructor$1.run()`,Method call: `void ImplicitConstructor.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] -codetoanalyze/java/starvation-whole-program/IndirectStarvation.java, IndirectStarvation.postBlockingCallToBackgroundThreadAndLockBad():void, 32, STARVATION, no_bucket, ERROR, [[Trace 1] `void IndirectStarvation.postBlockingCallToBackgroundThreadAndLockBad()`,Method call: `void IndirectStarvation$1.run()`, locks `this.monitorA` in `class IndirectStarvation`,[Trace 2] `void IndirectStarvation.postBlockingCallToBackgroundThreadAndLockBad()`,Method call: `void IndirectStarvation$2.run()`, locks `this.monitorA` in `class IndirectStarvation`,Method call: `void IndirectStarvation.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] +codetoanalyze/java/starvation-whole-program/IndirectStarvation.java, IndirectStarvation.postBlockingCallToBackgroundThreadAndLockBad():void, 32, STARVATION, no_bucket, ERROR, [[Trace 1] `void IndirectStarvation.postBlockingCallToBackgroundThreadAndLockBad()`,Method call: `void IndirectStarvation$1.run()`, locks `this.this$0.monitorA` in `class IndirectStarvation$1`,[Trace 2] `void IndirectStarvation.postBlockingCallToBackgroundThreadAndLockBad()`,Method call: `void IndirectStarvation$2.run()`, locks `this.this$0.monitorA` in `class IndirectStarvation$2`,Method call: `void IndirectStarvation.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] codetoanalyze/java/starvation-whole-program/ModeledExecutors.java, ModeledExecutors.postToUIThreadBad():void, 165, STARVATION, no_bucket, ERROR, [`void ModeledExecutors.postToUIThreadBad()`,Method call: `void ModeledExecutors$12.run()`,Method call: `void ModeledExecutors.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] codetoanalyze/java/starvation-whole-program/ModeledExecutors.java, ModeledExecutors.scheduleBlockingCallToUIThreadBad():void, 140, STARVATION, no_bucket, ERROR, [`void ModeledExecutors.scheduleBlockingCallToUIThreadBad()`,Method call: `void ModeledExecutors$10.run()`,Method call: `void ModeledExecutors.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] -codetoanalyze/java/starvation-whole-program/ModeledExecutors.java, ModeledExecutors.scheduleGuaranteedDelayedDeadlockBad():void, 97, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void ModeledExecutors.scheduleGuaranteedDelayedDeadlockBad()`,Method call: `void ModeledExecutors$7.run()`, locks `this.monitorA` in `class ModeledExecutors`, locks `this.monitorB` in `class ModeledExecutors`,[Trace 2] `void ModeledExecutors.scheduleGuaranteedDelayedDeadlockBad()`,Method call: `void ModeledExecutors$8.run()`, locks `this.monitorB` in `class ModeledExecutors`, locks `this.monitorA` in `class ModeledExecutors`] -codetoanalyze/java/starvation-whole-program/ModeledExecutors.java, ModeledExecutors.scheduleGuaranteedDelayedDeadlockBad():void, 110, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void ModeledExecutors.scheduleGuaranteedDelayedDeadlockBad()`,Method call: `void ModeledExecutors$8.run()`, locks `this.monitorB` in `class ModeledExecutors`, locks `this.monitorA` in `class ModeledExecutors`,[Trace 2] `void ModeledExecutors.scheduleGuaranteedDelayedDeadlockBad()`,Method call: `void ModeledExecutors$7.run()`, locks `this.monitorA` in `class ModeledExecutors`, locks `this.monitorB` in `class ModeledExecutors`] +codetoanalyze/java/starvation-whole-program/ModeledExecutors.java, ModeledExecutors.scheduleGuaranteedDelayedDeadlockBad():void, 97, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void ModeledExecutors.scheduleGuaranteedDelayedDeadlockBad()`,Method call: `void ModeledExecutors$7.run()`, locks `this.this$0.monitorA` in `class ModeledExecutors$7`, locks `this.this$0.monitorB` in `class ModeledExecutors$7`,[Trace 2] `void ModeledExecutors.scheduleGuaranteedDelayedDeadlockBad()`,Method call: `void ModeledExecutors$8.run()`, locks `this.this$0.monitorB` in `class ModeledExecutors$8`, locks `this.this$0.monitorA` in `class ModeledExecutors$8`] +codetoanalyze/java/starvation-whole-program/ModeledExecutors.java, ModeledExecutors.scheduleGuaranteedDelayedDeadlockBad():void, 110, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void ModeledExecutors.scheduleGuaranteedDelayedDeadlockBad()`,Method call: `void ModeledExecutors$8.run()`, locks `this.this$0.monitorB` in `class ModeledExecutors$8`, locks `this.this$0.monitorA` in `class ModeledExecutors$8`,[Trace 2] `void ModeledExecutors.scheduleGuaranteedDelayedDeadlockBad()`,Method call: `void ModeledExecutors$7.run()`, locks `this.this$0.monitorA` in `class ModeledExecutors$7`, locks `this.this$0.monitorB` in `class ModeledExecutors$7`] codetoanalyze/java/starvation-whole-program/ModeledExecutors.java, ModeledExecutors.staticPostBlockingCallToUIThreadBad():void, 50, STARVATION, no_bucket, ERROR, [`void ModeledExecutors.staticPostBlockingCallToUIThreadBad()`,Method call: `void ModeledExecutors$3.run()`,Method call: `void ModeledExecutors.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] codetoanalyze/java/starvation-whole-program/ModeledExecutors.java, ModeledExecutors.staticPostDelayedBlockingCallToUIThreadBad():void, 72, STARVATION, no_bucket, ERROR, [`void ModeledExecutors.staticPostDelayedBlockingCallToUIThreadBad()`,Method call: `void ModeledExecutors$5.run()`,Method call: `void ModeledExecutors.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] codetoanalyze/java/starvation-whole-program/ModeledExecutors.java, ModeledExecutors.staticRunBlockingCallToUIThreadBad():void, 61, STARVATION, no_bucket, ERROR, [`void ModeledExecutors.staticRunBlockingCallToUIThreadBad()`,Method call: `void ModeledExecutors$4.run()`,Method call: `void ModeledExecutors.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] @@ -22,24 +22,24 @@ codetoanalyze/java/starvation-whole-program/ModeledExecutors.java, ModeledExecut codetoanalyze/java/starvation-whole-program/ModeledExecutors.java, ModeledExecutors.submitBlockingCallToUIThreadBad():void, 127, STARVATION, no_bucket, ERROR, [`void ModeledExecutors.submitBlockingCallToUIThreadBad()`,Method call: `void ModeledExecutors$9.run()`,Method call: `void ModeledExecutors.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] codetoanalyze/java/starvation-whole-program/ModeledHandler.java, ModeledHandler.postBlockingCallToUIThreadBad():void, 27, STARVATION, no_bucket, ERROR, [`void ModeledHandler.postBlockingCallToUIThreadBad()`,Method call: `void ModeledHandler$1.run()`,Method call: `void ModeledHandler.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] codetoanalyze/java/starvation-whole-program/MyActivity.java, MyActivity.onCreate(android.os.Bundle):void, 28, STARVATION, no_bucket, ERROR, [`void MyActivity.onCreate(Bundle)`,Method call: `void MyActivity.bad()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] -codetoanalyze/java/starvation-whole-program/MyActivity.java, MyActivity.onDestroy():void, 68, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void MyActivity.onDestroy()`, locks `this.monitorC` in `class MyActivity`, locks `this.monitorB` in `class MyActivity`,[Trace 2] `void MyActivity.onPause()`,Method call: `void MyActivity$2.run()`, locks `this.monitorB` in `class MyActivity`, locks `this.monitorC` in `class MyActivity`] -codetoanalyze/java/starvation-whole-program/MyActivity.java, MyActivity.onPause():void, 76, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void MyActivity.onPause()`,Method call: `void MyActivity$2.run()`, locks `this.monitorB` in `class MyActivity`, locks `this.monitorC` in `class MyActivity`,[Trace 2] `void MyActivity.onDestroy()`, locks `this.monitorC` in `class MyActivity`, locks `this.monitorB` in `class MyActivity`] +codetoanalyze/java/starvation-whole-program/MyActivity.java, MyActivity.onDestroy():void, 68, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void MyActivity.onDestroy()`, locks `this.monitorC` in `class MyActivity`, locks `this.monitorB` in `class MyActivity`,[Trace 2] `void MyActivity.onPause()`,Method call: `void MyActivity$2.run()`, locks `this.this$0.monitorB` in `class MyActivity$2`, locks `this.this$0.monitorC` in `class MyActivity$2`] +codetoanalyze/java/starvation-whole-program/MyActivity.java, MyActivity.onPause():void, 76, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void MyActivity.onPause()`,Method call: `void MyActivity$2.run()`, locks `this.this$0.monitorB` in `class MyActivity$2`, locks `this.this$0.monitorC` in `class MyActivity$2`,[Trace 2] `void MyActivity.onDestroy()`, locks `this.monitorC` in `class MyActivity`, locks `this.monitorB` in `class MyActivity`] codetoanalyze/java/starvation-whole-program/MyActivity.java, MyActivity.onRestart():void, 38, STARVATION, no_bucket, ERROR, [`void MyActivity.onRestart()`,Method call: `void MyActivity.bad()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] -codetoanalyze/java/starvation-whole-program/MyActivity.java, MyActivity.onResume():void, 95, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void MyActivity.onResume()`, locks `this.FP_monitorD` in `class MyActivity`, locks `this.FP_monitorE` in `class MyActivity`,[Trace 2] `void MyActivity.onResume()`,Method call: `void MyActivity$3.run()`, locks `this.FP_monitorE` in `class MyActivity`, locks `this.FP_monitorD` in `class MyActivity`] -codetoanalyze/java/starvation-whole-program/MyActivity.java, MyActivity.onResume():void, 100, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void MyActivity.onResume()`,Method call: `void MyActivity$3.run()`, locks `this.FP_monitorE` in `class MyActivity`, locks `this.FP_monitorD` in `class MyActivity`,[Trace 2] `void MyActivity.onResume()`, locks `this.FP_monitorD` in `class MyActivity`, locks `this.FP_monitorE` in `class MyActivity`] +codetoanalyze/java/starvation-whole-program/MyActivity.java, MyActivity.onResume():void, 95, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void MyActivity.onResume()`, locks `this.FP_monitorD` in `class MyActivity`, locks `this.FP_monitorE` in `class MyActivity`,[Trace 2] `void MyActivity.onResume()`,Method call: `void MyActivity$3.run()`, locks `this.this$0.FP_monitorE` in `class MyActivity$3`, locks `this.this$0.FP_monitorD` in `class MyActivity$3`] +codetoanalyze/java/starvation-whole-program/MyActivity.java, MyActivity.onResume():void, 100, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void MyActivity.onResume()`,Method call: `void MyActivity$3.run()`, locks `this.this$0.FP_monitorE` in `class MyActivity$3`, locks `this.this$0.FP_monitorD` in `class MyActivity$3`,[Trace 2] `void MyActivity.onResume()`, locks `this.FP_monitorD` in `class MyActivity`, locks `this.FP_monitorE` in `class MyActivity`] codetoanalyze/java/starvation-whole-program/MyActivity.java, MyActivity.onStart():void, 33, STARVATION, no_bucket, ERROR, [`void MyActivity.onStart()`,Method call: `void MyActivity.bad()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] -codetoanalyze/java/starvation-whole-program/MyActivity.java, MyActivity.onStop():void, 48, STARVATION, no_bucket, ERROR, [[Trace 1] `void MyActivity.onStop()`, locks `this.monitorA` in `class MyActivity`,[Trace 2] `void MyActivity.onStop()`,Method call: `void MyActivity$1.run()`, locks `this.monitorA` in `class MyActivity`,Method call: `void MyActivity.bad()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] +codetoanalyze/java/starvation-whole-program/MyActivity.java, MyActivity.onStop():void, 48, STARVATION, no_bucket, ERROR, [[Trace 1] `void MyActivity.onStop()`, locks `this.monitorA` in `class MyActivity`,[Trace 2] `void MyActivity.onStop()`,Method call: `void MyActivity$1.run()`, locks `this.this$0.monitorA` in `class MyActivity$1`,Method call: `void MyActivity.bad()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] codetoanalyze/java/starvation-whole-program/MyServiceConnection.java, MyServiceConnection.onBindingDied(android.content.ComponentName):void, 27, STARVATION, no_bucket, ERROR, [`void MyServiceConnection.onBindingDied(ComponentName)`,Method call: `void MyServiceConnection.bad()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] codetoanalyze/java/starvation-whole-program/MyServiceConnection.java, MyServiceConnection.onNullBinding(android.content.ComponentName):void, 31, STARVATION, no_bucket, ERROR, [`void MyServiceConnection.onNullBinding(ComponentName)`,Method call: `void MyServiceConnection.bad()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] codetoanalyze/java/starvation-whole-program/MyServiceConnection.java, MyServiceConnection.onServiceConnected(android.content.ComponentName,android.os.IBinder):void, 36, STARVATION, no_bucket, ERROR, [`void MyServiceConnection.onServiceConnected(ComponentName,IBinder)`,Method call: `void MyServiceConnection.bad()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] codetoanalyze/java/starvation-whole-program/MyServiceConnection.java, MyServiceConnection.onServiceDisconnected(android.content.ComponentName):void, 41, STARVATION, no_bucket, ERROR, [`void MyServiceConnection.onServiceDisconnected(ComponentName)`,Method call: `void MyServiceConnection.bad()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] codetoanalyze/java/starvation-whole-program/StaticInitAttributes.java, StaticInitAttributes.postBlockingCallToUIExecutorBad():void, 52, STARVATION, no_bucket, ERROR, [`void StaticInitAttributes.postBlockingCallToUIExecutorBad()`,Method call: `void StaticInitAttributes$1.run()`,Method call: `void StaticInitAttributes.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] codetoanalyze/java/starvation-whole-program/StaticInitAttributes.java, StaticInitAttributes.postBlockingCallToUIHandlerBad():void, 64, STARVATION, no_bucket, ERROR, [`void StaticInitAttributes.postBlockingCallToUIHandlerBad()`,Method call: `void StaticInitAttributes$1.run()`,Method call: `void StaticInitAttributes.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] -codetoanalyze/java/starvation-whole-program/ThreadScheduling.java, ThreadScheduling.scheduleBlockingCallOnContendedLockBad():void, 36, STARVATION, no_bucket, ERROR, [[Trace 1] `void ThreadScheduling.scheduleBlockingCallOnContendedLockBad()`,Method call: `void ThreadScheduling$2.run()`, locks `this.monitorA` in `class ThreadScheduling`,[Trace 2] `void ThreadScheduling.scheduleBlockingCallOnContendedLockBad()`,Method call: `void ThreadScheduling$1.run()`, locks `this.monitorA` in `class ThreadScheduling`,Method call: `void ThreadScheduling.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] -codetoanalyze/java/starvation-whole-program/ThreadScheduling.java, ThreadScheduling.scheduleBlockingCallOnContendedLockViaInheritanceBad():void, 89, STARVATION, no_bucket, ERROR, [[Trace 1] `void ThreadScheduling.scheduleBlockingCallOnContendedLockViaInheritanceBad()`,Method call: `void ThreadScheduling$5.run()`, locks `this.monitorD` in `class ThreadScheduling`,[Trace 2] `void ThreadScheduling.scheduleBlockingCallOnContendedLockViaInheritanceBad()`,Method call: `void ThreadScheduling$BadThread.run()`, locks `this.monitorD` in `class ThreadScheduling`,Method call: `void ThreadScheduling.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] -codetoanalyze/java/starvation-whole-program/ThreadScheduling.java, ThreadScheduling.scheduleDeadlockBad():void, 60, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void ThreadScheduling.scheduleDeadlockBad()`,Method call: `void ThreadScheduling$3.run()`, locks `this.monitorB` in `class ThreadScheduling`, locks `this.monitorC` in `class ThreadScheduling`,[Trace 2] `void ThreadScheduling.scheduleDeadlockBad()`,Method call: `void ThreadScheduling$4.run()`, locks `this.monitorC` in `class ThreadScheduling`, locks `this.monitorB` in `class ThreadScheduling`] -codetoanalyze/java/starvation-whole-program/ThreadScheduling.java, ThreadScheduling.scheduleDeadlockBad():void, 62, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void ThreadScheduling.scheduleDeadlockBad()`,Method call: `void ThreadScheduling$4.run()`, locks `this.monitorC` in `class ThreadScheduling`, locks `this.monitorB` in `class ThreadScheduling`,[Trace 2] `void ThreadScheduling.scheduleDeadlockBad()`,Method call: `void ThreadScheduling$3.run()`, locks `this.monitorB` in `class ThreadScheduling`, locks `this.monitorC` in `class ThreadScheduling`] -codetoanalyze/java/starvation-whole-program/UnknownThread.java, UnknownThread.postDeadlockToUIAndBackgroundBad():void, 84, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void UnknownThread.postDeadlockToUIAndBackgroundBad()`,Method call: `void UnknownThread$5.run()`, locks `this.monitorC` in `class UnknownThread`, locks `this.monitorD` in `class UnknownThread`,[Trace 2] `void UnknownThread.postDeadlockToUIAndBackgroundBad()`,Method call: `void UnknownThread$6.run()`, locks `this.monitorD` in `class UnknownThread`, locks `this.monitorC` in `class UnknownThread`] -codetoanalyze/java/starvation-whole-program/UnknownThread.java, UnknownThread.postDeadlockToUIAndBackgroundBad():void, 95, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void UnknownThread.postDeadlockToUIAndBackgroundBad()`,Method call: `void UnknownThread$6.run()`, locks `this.monitorD` in `class UnknownThread`, locks `this.monitorC` in `class UnknownThread`,[Trace 2] `void UnknownThread.postDeadlockToUIAndBackgroundBad()`,Method call: `void UnknownThread$5.run()`, locks `this.monitorC` in `class UnknownThread`, locks `this.monitorD` in `class UnknownThread`] -codetoanalyze/java/starvation-whole-program/UnknownThread.java, UnknownThread.postDeadlockToUnknownAndBackgroundBad():void, 57, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void UnknownThread.postDeadlockToUnknownAndBackgroundBad()`,Method call: `void UnknownThread$3.run()`, locks `this.monitorA` in `class UnknownThread`, locks `this.monitorB` in `class UnknownThread`,[Trace 2] `void UnknownThread.postDeadlockToUnknownAndBackgroundBad()`,Method call: `void UnknownThread$4.run()`, locks `this.monitorB` in `class UnknownThread`, locks `this.monitorA` in `class UnknownThread`] -codetoanalyze/java/starvation-whole-program/UnknownThread.java, UnknownThread.postDeadlockToUnknownAndBackgroundBad():void, 68, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void UnknownThread.postDeadlockToUnknownAndBackgroundBad()`,Method call: `void UnknownThread$4.run()`, locks `this.monitorB` in `class UnknownThread`, locks `this.monitorA` in `class UnknownThread`,[Trace 2] `void UnknownThread.postDeadlockToUnknownAndBackgroundBad()`,Method call: `void UnknownThread$3.run()`, locks `this.monitorA` in `class UnknownThread`, locks `this.monitorB` in `class UnknownThread`] +codetoanalyze/java/starvation-whole-program/ThreadScheduling.java, ThreadScheduling.scheduleBlockingCallOnContendedLockBad():void, 36, STARVATION, no_bucket, ERROR, [[Trace 1] `void ThreadScheduling.scheduleBlockingCallOnContendedLockBad()`,Method call: `void ThreadScheduling$2.run()`, locks `this.this$0.monitorA` in `class ThreadScheduling$2`,[Trace 2] `void ThreadScheduling.scheduleBlockingCallOnContendedLockBad()`,Method call: `void ThreadScheduling$1.run()`, locks `this.this$0.monitorA` in `class ThreadScheduling$1`,Method call: `void ThreadScheduling.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] +codetoanalyze/java/starvation-whole-program/ThreadScheduling.java, ThreadScheduling.scheduleBlockingCallOnContendedLockViaInheritanceBad():void, 89, STARVATION, no_bucket, ERROR, [[Trace 1] `void ThreadScheduling.scheduleBlockingCallOnContendedLockViaInheritanceBad()`,Method call: `void ThreadScheduling$5.run()`, locks `this.this$0.monitorD` in `class ThreadScheduling$5`,[Trace 2] `void ThreadScheduling.scheduleBlockingCallOnContendedLockViaInheritanceBad()`,Method call: `void ThreadScheduling$BadThread.run()`, locks `this.this$0.monitorD` in `class ThreadScheduling$BadThread`,Method call: `void ThreadScheduling.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`] +codetoanalyze/java/starvation-whole-program/ThreadScheduling.java, ThreadScheduling.scheduleDeadlockBad():void, 60, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void ThreadScheduling.scheduleDeadlockBad()`,Method call: `void ThreadScheduling$3.run()`, locks `this.this$0.monitorB` in `class ThreadScheduling$3`, locks `this.this$0.monitorC` in `class ThreadScheduling$3`,[Trace 2] `void ThreadScheduling.scheduleDeadlockBad()`,Method call: `void ThreadScheduling$4.run()`, locks `this.this$0.monitorC` in `class ThreadScheduling$4`, locks `this.this$0.monitorB` in `class ThreadScheduling$4`] +codetoanalyze/java/starvation-whole-program/ThreadScheduling.java, ThreadScheduling.scheduleDeadlockBad():void, 62, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void ThreadScheduling.scheduleDeadlockBad()`,Method call: `void ThreadScheduling$4.run()`, locks `this.this$0.monitorC` in `class ThreadScheduling$4`, locks `this.this$0.monitorB` in `class ThreadScheduling$4`,[Trace 2] `void ThreadScheduling.scheduleDeadlockBad()`,Method call: `void ThreadScheduling$3.run()`, locks `this.this$0.monitorB` in `class ThreadScheduling$3`, locks `this.this$0.monitorC` in `class ThreadScheduling$3`] +codetoanalyze/java/starvation-whole-program/UnknownThread.java, UnknownThread.postDeadlockToUIAndBackgroundBad():void, 84, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void UnknownThread.postDeadlockToUIAndBackgroundBad()`,Method call: `void UnknownThread$5.run()`, locks `this.this$0.monitorC` in `class UnknownThread$5`, locks `this.this$0.monitorD` in `class UnknownThread$5`,[Trace 2] `void UnknownThread.postDeadlockToUIAndBackgroundBad()`,Method call: `void UnknownThread$6.run()`, locks `this.this$0.monitorD` in `class UnknownThread$6`, locks `this.this$0.monitorC` in `class UnknownThread$6`] +codetoanalyze/java/starvation-whole-program/UnknownThread.java, UnknownThread.postDeadlockToUIAndBackgroundBad():void, 95, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void UnknownThread.postDeadlockToUIAndBackgroundBad()`,Method call: `void UnknownThread$6.run()`, locks `this.this$0.monitorD` in `class UnknownThread$6`, locks `this.this$0.monitorC` in `class UnknownThread$6`,[Trace 2] `void UnknownThread.postDeadlockToUIAndBackgroundBad()`,Method call: `void UnknownThread$5.run()`, locks `this.this$0.monitorC` in `class UnknownThread$5`, locks `this.this$0.monitorD` in `class UnknownThread$5`] +codetoanalyze/java/starvation-whole-program/UnknownThread.java, UnknownThread.postDeadlockToUnknownAndBackgroundBad():void, 57, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void UnknownThread.postDeadlockToUnknownAndBackgroundBad()`,Method call: `void UnknownThread$3.run()`, locks `this.this$0.monitorA` in `class UnknownThread$3`, locks `this.this$0.monitorB` in `class UnknownThread$3`,[Trace 2] `void UnknownThread.postDeadlockToUnknownAndBackgroundBad()`,Method call: `void UnknownThread$4.run()`, locks `this.this$0.monitorB` in `class UnknownThread$4`, locks `this.this$0.monitorA` in `class UnknownThread$4`] +codetoanalyze/java/starvation-whole-program/UnknownThread.java, UnknownThread.postDeadlockToUnknownAndBackgroundBad():void, 68, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void UnknownThread.postDeadlockToUnknownAndBackgroundBad()`,Method call: `void UnknownThread$4.run()`, locks `this.this$0.monitorB` in `class UnknownThread$4`, locks `this.this$0.monitorA` in `class UnknownThread$4`,[Trace 2] `void UnknownThread.postDeadlockToUnknownAndBackgroundBad()`,Method call: `void UnknownThread$3.run()`, locks `this.this$0.monitorA` in `class UnknownThread$3`, locks `this.this$0.monitorB` in `class UnknownThread$3`]