From 971cd84455f26e3ee9d91d1fce89647a04e67e61 Mon Sep 17 00:00:00 2001 From: Nikos Gorogiannis Date: Mon, 4 Jun 2018 08:36:46 -0700 Subject: [PATCH] [starvation] report using split events Summary: Use the component of the abstract state `events` to report. This set contains reachability facts about blocking calls and lock acquisitions. The other component, `order`, contained pairs of a reachable event `e'` from an event option with the semantics that if the option is `None` then we have an element that now goes into `events`, and if the option is `Some e` then the element represents a lock acquired and a trace *from* `e` to `e'` Now, `order` can be simplified to proper pairs of events, without the option. Reviewed By: jvillard Differential Revision: D8227665 fbshipit-source-id: e6f4dac --- infer/src/concurrency/starvation.ml | 66 +++----- infer/src/concurrency/starvationDomain.ml | 147 ++++++++---------- infer/src/concurrency/starvationDomain.mli | 14 +- .../codetoanalyze/java/starvation/issues.exp | 66 ++++---- 4 files changed, 128 insertions(+), 165 deletions(-) diff --git a/infer/src/concurrency/starvation.ml b/infer/src/concurrency/starvation.ml index 8a46952a3..3e5f83c88 100644 --- a/infer/src/concurrency/starvation.ml +++ b/infer/src/concurrency/starvation.ml @@ -132,20 +132,6 @@ let analyze_procedure {Callbacks.proc_desc; tenv; summary} = |> Option.value_map ~default:summary ~f:(fun astate -> Payload.update_summary astate summary) -let make_trace_with_header ?(header= "") elem pname = - let trace = StarvationDomain.Order.make_loc_trace elem in - let trace_descr = Format.asprintf "%s %a" header (MF.wrap_monospaced Typ.Procname.pp) pname in - let start_loc = - List.hd trace |> Option.value_map ~default:Location.dummy ~f:(fun lt -> lt.Errlog.lt_loc) - in - Errlog.make_trace_element 0 start_loc trace_descr [] :: trace - - -let make_loc_trace pname trace_id elem = - let header = Printf.sprintf "[Trace %d] " trace_id in - make_trace_with_header ~header elem pname - - let get_summaries_of_methods_in_class tenv clazz = let tstruct_opt = Tenv.lookup tenv clazz in let methods = @@ -218,21 +204,21 @@ end let should_report_deadlock_on_current_proc current_elem endpoint_elem = let open StarvationDomain in match (current_elem.Order.first, current_elem.Order.eventually) with - | None, _ | Some {Event.elem= MayBlock _}, _ | _, {Event.elem= MayBlock _} -> + | {Event.elem= MayBlock _}, _ | _, {Event.elem= MayBlock _} -> (* should never happen *) L.die InternalError "Deadlock cannot occur without two lock events: %a" Order.pp current_elem - | Some {Event.elem= LockAcquire ((Var.LogicalVar _, _), [])}, _ -> + | {Event.elem= LockAcquire ((Var.LogicalVar _, _), [])}, _ -> (* first elem is a class object (see [lock_of_class]), so always report because the reverse ordering on the events will not occur *) true - | Some {Event.elem= LockAcquire ((Var.LogicalVar _, _), _ :: _)}, _ + | {Event.elem= LockAcquire ((Var.LogicalVar _, _), _ :: _)}, _ | _, {Event.elem= LockAcquire ((Var.LogicalVar _, _), _)} -> (* first elem has an ident root, but has a non-empty access path, which means we are not filtering out local variables (see [exec_instr]), or, second elem has an ident root, which should not happen if we are filtering locals *) L.die InternalError "Deadlock cannot occur on these logical variables: %a @." Order.pp current_elem - | Some {Event.elem= LockAcquire ((_, typ1), _)}, {Event.elem= LockAcquire ((_, typ2), _)} -> + | {Event.elem= LockAcquire ((_, typ1), _)}, {Event.elem= LockAcquire ((_, typ2), _)} -> (* use string comparison on types as a stable order to decide whether to report a deadlock *) let c = String.compare (Typ.to_string typ1) (Typ.to_string typ2) in c < 0 @@ -271,9 +257,9 @@ let report_deadlocks tenv current_pdesc {StarvationDomain.order; ui} report_map' (MF.wrap_monospaced Typ.Procname.pp) endpoint_pname Order.pp elem in - let first_trace = List.rev (make_loc_trace current_pname 1 current_elem) in - let second_trace = make_loc_trace endpoint_pname 2 elem in - let ltr = List.rev_append first_trace second_trace in + let first_trace = Order.make_trace ~header:"[Trace 1] " current_pname current_elem in + let second_trace = Order.make_trace ~header:"[Trace 2] " endpoint_pname elem in + let ltr = first_trace @ second_trace in let loc = Order.get_loc current_elem in ReportMap.add_deadlock current_pname loc ltr error_message report_map | _, _ -> @@ -281,7 +267,7 @@ let report_deadlocks tenv current_pdesc {StarvationDomain.order; ui} report_map' in let report_on_current_elem elem report_map = match elem with - | {Order.first= None} | {Order.eventually= {Event.elem= Event.MayBlock _}} -> + | {Order.eventually= {Event.elem= Event.MayBlock _}} -> report_map | {Order.eventually= {Event.elem= Event.LockAcquire endpoint_lock}} -> Lock.owner_class endpoint_lock @@ -301,14 +287,12 @@ let report_deadlocks tenv current_pdesc {StarvationDomain.order; ui} report_map' OrderDomain.fold report_on_current_elem order report_map' -let report_starvation tenv current_pdesc {StarvationDomain.order; ui} report_map' = +let report_starvation tenv current_pdesc {StarvationDomain.events; ui} report_map' = let open StarvationDomain in let current_pname = Procdesc.get_proc_name current_pdesc in - let report_remote_block ui_explain current_elem current_lock endpoint_pname endpoint_elem - report_map = - match endpoint_elem with - | { Order.first= Some {Event.elem= Event.LockAcquire lock} - ; eventually= {Event.elem= Event.MayBlock (block_descr, sev)} } + let report_remote_block ui_explain event current_lock endpoint_pname endpoint_elem report_map = + match (endpoint_elem.Order.first, endpoint_elem.Order.eventually) with + | {Event.elem= Event.LockAcquire lock}, {Event.elem= Event.MayBlock (block_descr, sev)} when Lock.equal current_lock lock -> let error_message = Format.asprintf @@ -317,26 +301,26 @@ let report_starvation tenv current_pdesc {StarvationDomain.order; ui} report_map (MF.wrap_monospaced Typ.Procname.pp) current_pname ui_explain Lock.pp lock block_descr in - let first_trace = List.rev (make_loc_trace current_pname 1 current_elem) in - let second_trace = make_loc_trace endpoint_pname 2 endpoint_elem in - let ltr = List.rev_append first_trace second_trace in - let loc = Order.get_loc current_elem in + let first_trace = Event.make_trace ~header:"[Trace 1] " current_pname event in + let second_trace = Order.make_trace ~header:"[Trace 2] " endpoint_pname endpoint_elem in + let ltr = first_trace @ second_trace in + let loc = Event.get_loc event in ReportMap.add_starvation sev current_pname loc ltr error_message report_map | _ -> report_map in - let report_on_current_elem ui_explain ({Order.eventually} as elem) report_map = - match eventually with - | {Event.elem= Event.MayBlock (_, sev)} -> + let report_on_current_elem ui_explain event report_map = + match event.Event.elem with + | Event.MayBlock (_, sev) -> let error_message = Format.asprintf "Method %a runs on UI thread (because %s), and may block; %a." (MF.wrap_monospaced Typ.Procname.pp) - current_pname ui_explain Event.pp_event eventually.Event.elem + current_pname ui_explain Event.pp_no_trace event in - let loc = Order.get_loc elem in - let ltr = make_trace_with_header elem current_pname in + let loc = Event.get_loc event in + let ltr = Event.make_trace current_pname event in ReportMap.add_starvation sev current_pname loc ltr error_message report_map - | {Event.elem= Event.LockAcquire endpoint_lock} -> + | Event.LockAcquire endpoint_lock -> Lock.owner_class endpoint_lock |> Option.value_map ~default:report_map ~f:(fun endpoint_class -> (* get the class of the root variable of the lock in the endpoint elem @@ -348,7 +332,7 @@ let report_starvation tenv current_pdesc {StarvationDomain.order; ui} report_map (* skip methods known to run on ui thread, as they cannot run in parallel to us *) if UIThreadDomain.is_empty ui then OrderDomain.fold - (report_remote_block ui_explain elem endpoint_lock endpoint_pname) + (report_remote_block ui_explain event endpoint_lock endpoint_pname) order acc else acc ) ) in @@ -356,7 +340,7 @@ let report_starvation tenv current_pdesc {StarvationDomain.order; ui} report_map | AbstractDomain.Types.Bottom -> report_map' | AbstractDomain.Types.NonBottom ui_explain -> - OrderDomain.fold (report_on_current_elem ui_explain) order report_map' + EventDomain.fold (report_on_current_elem ui_explain) events report_map' let reporting {Callbacks.procedures; exe_env} = diff --git a/infer/src/concurrency/starvationDomain.ml b/infer/src/concurrency/starvationDomain.ml index 87bc37ddf..75998631f 100644 --- a/infer/src/concurrency/starvationDomain.ml +++ b/infer/src/concurrency/starvationDomain.ml @@ -57,13 +57,17 @@ module type TraceElem = sig include PrettyPrintable.PrintableOrderedType with type t := t + val pp_no_trace : F.formatter -> t -> unit + val make : elem_t -> Location.t -> t val get_loc : t -> Location.t - val make_loc_trace : ?reverse:bool -> t -> Errlog.loc_trace + val make_loc_trace : t -> Errlog.loc_trace val with_callsite : t -> CallSite.t -> t + + val make_trace : ?header:string -> Typ.Procname.t -> t -> Errlog.loc_trace end module MakeTraceElem (Elem : PrettyPrintable.PrintableOrderedType) : @@ -74,6 +78,8 @@ struct type t = {elem: Elem.t; loc: Location.t; trace: CallSite.t list [@compare.ignore]} [@@deriving compare] + let pp_no_trace fmt {elem; loc} = F.fprintf fmt "%a at %a" Elem.pp elem Location.pp loc + let pp fmt e = let pp_trace fmt = function | [] -> @@ -81,14 +87,14 @@ struct | trace -> F.fprintf fmt " (trace: %a)" (Pp.semicolon_seq CallSite.pp) trace in - F.fprintf fmt "%a at %a%a" Elem.pp e.elem Location.pp e.loc pp_trace e.trace + F.fprintf fmt "%a%a" pp_no_trace e pp_trace e.trace let make elem loc = {elem; loc; trace= []} let get_loc {loc; trace} = List.hd trace |> Option.value_map ~default:loc ~f:CallSite.loc - let make_loc_trace ?(reverse= false) e = + let make_loc_trace e = let call_trace, nesting = List.fold e.trace ~init:([], 0) ~f:(fun (tr, ns) callsite -> let elem_descr = @@ -101,11 +107,17 @@ struct in let endpoint_descr = F.asprintf "%a" Elem.pp e.elem in let endpoint = Errlog.make_trace_element nesting e.loc endpoint_descr [] in - let res = endpoint :: call_trace in - if reverse then res else List.rev res + List.rev (endpoint :: call_trace) let with_callsite elem callsite = {elem with trace= callsite :: elem.trace} + + let make_trace ?(header= "") pname elem = + let trace = make_loc_trace elem in + let trace_descr = Format.asprintf "%s%a" header (MF.wrap_monospaced Typ.Procname.pp) pname in + let start_loc = get_loc elem in + let header_step = Errlog.make_trace_element 0 start_loc trace_descr [] in + header_step :: trace end module Event = struct @@ -113,29 +125,18 @@ module Event = struct type event_t = LockAcquire of Lock.t | MayBlock of (string * severity_t) [@@deriving compare] - let pp_event fmt = function - | LockAcquire lock -> - Lock.pp fmt lock - | MayBlock (msg, _) -> - F.pp_print_string fmt msg - - include MakeTraceElem (struct type t = event_t [@@deriving compare] - let pp = pp_event + let pp fmt = function + | LockAcquire lock -> + Lock.pp fmt lock + | MayBlock (msg, _) -> + F.pp_print_string fmt msg end) let is_lock_event e = match e.elem with LockAcquire _ -> true | _ -> false - let locks_equal e e' = - match (e.elem, e'.elem) with - | LockAcquire lock, LockAcquire lock' -> - Lock.equal lock lock' - | _, _ -> - false - - let locks_equal_modulo_base e e' = match (e.elem, e'.elem) with | LockAcquire lock, LockAcquire lock' -> @@ -165,56 +166,45 @@ module EventDomain = struct end module Order = struct - type t = {first: Event.t option; eventually: Event.t} [@@deriving compare] + type t = {first: Event.t; eventually: Event.t} [@@deriving compare] - let pp fmt o = - match o.first with - | None -> - F.fprintf fmt "eventually %a" Event.pp o.eventually - | Some lock -> - F.fprintf fmt "first %a, and before releasing it, %a" Event.pp lock Event.pp o.eventually + let pp fmt {first; eventually} = + F.fprintf fmt "first %a, and before releasing it, %a" Event.pp first Event.pp eventually - let may_deadlock elem elem' = - match (elem.first, elem'.first) with - | Some b, Some b' -> - Event.locks_equal_modulo_base b elem'.eventually - && Event.locks_equal_modulo_base b' elem.eventually - | _, _ -> - false + let may_deadlock {first; eventually} {first= first'; eventually= eventually'} = + Event.locks_equal_modulo_base first eventually' + && Event.locks_equal_modulo_base first' eventually - let make_eventually eventually = {first= None; eventually} + let make first eventually = + if not (Event.is_lock_event first) then L.(die InternalError) "Expected a lock elem first." ; + {first; eventually} - let make_first_and_eventually b eventually = - if not (Event.is_lock_event b) then L.(die InternalError) "Expected a lock elem first." ; - {first= Some b; eventually} + let with_callsite o callsite = {o with first= Event.with_callsite o.first callsite} - let with_callsite callsite o = {o with eventually= Event.with_callsite o.eventually callsite} + let get_loc {first} = Event.get_loc first - let get_loc {first; eventually} = - match first with Some elem -> Event.get_loc elem | None -> Event.get_loc eventually + let make_loc_trace {first; eventually} = + let first_trace = Event.make_loc_trace first in + let eventually_trace = Event.make_loc_trace eventually in + first_trace @ eventually_trace - let make_loc_trace o = - let first_trace = - Option.value_map o.first ~default:[] ~f:(Event.make_loc_trace ~reverse:true) - in - let eventually_trace = Event.make_loc_trace o.eventually in - List.rev_append first_trace eventually_trace + let make_trace ?(header= "") pname elem = + let trace = make_loc_trace elem in + let trace_descr = Format.asprintf "%s%a" header (MF.wrap_monospaced Typ.Procname.pp) pname in + let start_loc = get_loc elem in + let header_step = Errlog.make_trace_element 0 start_loc trace_descr [] in + header_step :: trace end module OrderDomain = struct include AbstractDomain.FiniteSet (Order) - let with_callsite callsite lo = - fold (fun o acc -> add (Order.with_callsite callsite o) acc) lo empty - - - let is_eventually_locked lock lo = - Event.is_lock_event lock - && exists (fun pair -> Event.locks_equal pair.Order.eventually lock) lo + let with_callsite lo callsite = + fold (fun o acc -> add (Order.with_callsite o callsite) acc) lo empty end module LockStack = AbstractDomain.StackDomain (Event) @@ -302,30 +292,23 @@ let ( <= ) ~lhs ~rhs = && LockState.( <= ) ~lhs:lhs.lock_state ~rhs:rhs.lock_state -(* for every lock b held locally, add a pair (b, lock_event), plus (None, lock_event) *) -let add_order_pairs order lock_event acc = +(* for every lock b held locally, add a pair (b, event) *) +let add_order_pairs lock_state event acc = (* add no pairs whatsoever if we already hold that lock *) - if LockState.is_taken lock_event order then acc + if LockState.is_taken event lock_state then acc else - let add_eventually acc = - (* don't add an eventually-locks pair if there is already another with same endpoint*) - if OrderDomain.is_eventually_locked lock_event acc then acc - else - let elem = Order.make_eventually lock_event in - OrderDomain.add elem acc - in let add_first_and_eventually acc first = (* never add a pair of the form (a,a) -- should never happen due to the check above *) - let elem = Order.make_first_and_eventually first lock_event in + let elem = Order.make first event in OrderDomain.add elem acc in - LockState.fold_over_events add_first_and_eventually order acc |> add_eventually + LockState.fold_over_events add_first_and_eventually lock_state acc -let acquire ({lock_state; events; order} as astate) loc lockid = - let new_event = Event.make_acquire lockid loc in +let acquire ({lock_state; events; order} as astate) loc lock = + let new_event = Event.make_acquire lock loc in { astate with - lock_state= LockState.acquire lockid new_event lock_state + lock_state= LockState.acquire lock new_event lock_state ; events= EventDomain.add new_event events ; order= add_order_pairs lock_state new_event order } @@ -336,27 +319,19 @@ let blocking_call ~caller ~callee sev loc ({lock_state; events; order} as astate events= EventDomain.add new_event events; order= add_order_pairs lock_state new_event order } -let release ({lock_state} as astate) lockid = - {astate with lock_state= LockState.release lockid lock_state} +let release ({lock_state} as astate) lock = + {astate with lock_state= LockState.release lock lock_state} let integrate_summary ({lock_state; events; order; ui} as astate) callee_pname loc callee_summary = - let callee_order = callee_summary.order in - let callee_ui = callee_summary.ui in - let callee_events = callee_summary.events in - (* for each pair (b,a) in the callee, add (l,b) and (l,a) to the current state, where - l is held locally *) - let do_elem elem acc = - Option.value_map elem.Order.first ~default:acc ~f:(fun b -> add_order_pairs lock_state b acc) - |> add_order_pairs lock_state elem.Order.eventually - in let callsite = CallSite.make callee_pname loc in - (* add callsite to the "eventually" trace *) - let elems = OrderDomain.with_callsite callsite callee_order in + let callee_order = OrderDomain.with_callsite callee_summary.order callsite in + let callee_events = EventDomain.with_callsite callee_summary.events callsite in + let order' = EventDomain.fold (add_order_pairs lock_state) callee_events callee_order in { astate with - events= EventDomain.join events (EventDomain.with_callsite callee_events callsite) - ; order= OrderDomain.fold do_elem elems order - ; ui= UIThreadDomain.join ui callee_ui } + events= EventDomain.join events callee_events + ; order= OrderDomain.join order order' + ; ui= UIThreadDomain.join ui callee_summary.ui } let set_on_ui_thread ({ui} as astate) explain = diff --git a/infer/src/concurrency/starvationDomain.mli b/infer/src/concurrency/starvationDomain.mli index 3867b35d8..94dfc25fe 100644 --- a/infer/src/concurrency/starvationDomain.mli +++ b/infer/src/concurrency/starvationDomain.mli @@ -25,11 +25,15 @@ module Event : sig type event_t = LockAcquire of Lock.t | MayBlock of (string * severity_t) [@@deriving compare] - val pp_event : F.formatter -> event_t -> unit - type t = private {elem: event_t; loc: Location.t; trace: CallSite.t list} include PrettyPrintable.PrintableOrderedType with type t := t + + val pp_no_trace : F.formatter -> t -> unit + + val get_loc : t -> Location.t + + val make_trace : ?header:string -> Typ.Procname.t -> t -> Errlog.loc_trace end module EventDomain : module type of AbstractDomain.FiniteSet (Event) @@ -40,7 +44,7 @@ module EventDomain : module type of AbstractDomain.FiniteSet (Event) - the "first" lock being taken *in the current method* and, before its release, the eventual acquisition of "eventually" *) module Order : sig - type t = private {first: Event.t option; eventually: Event.t} + type t = private {first: Event.t; eventually: Event.t} include PrettyPrintable.PrintableOrderedType with type t := t @@ -48,9 +52,9 @@ module Order : sig (** check if two pairs are symmetric in terms of locks, where locks are compared modulo the variable name at the root of each path. *) - val make_loc_trace : t -> Errlog.loc_trace - val get_loc : t -> Location.t + + val make_trace : ?header:string -> Typ.Procname.t -> t -> Errlog.loc_trace end module OrderDomain : sig diff --git a/infer/tests/codetoanalyze/java/starvation/issues.exp b/infer/tests/codetoanalyze/java/starvation/issues.exp index d6c3f6d8d..bacfea19c 100644 --- a/infer/tests/codetoanalyze/java/starvation/issues.exp +++ b/infer/tests/codetoanalyze/java/starvation/issues.exp @@ -1,33 +1,33 @@ -codetoanalyze/java/starvation/AccMgr.java, void AccMgr.lockOnUiThreadBad(), 25, STARVATION, no_bucket, ERROR, [[Trace 1] `void AccMgr.lockOnUiThreadBad()`,locks `this.AccMgr.lock` in class `AccMgr*`,[Trace 2] `void AccMgr.setUserDataUnderLock()`,locks `this.AccMgr.lock` in class `AccMgr*`,calls `void AccountManager.setUserData(Account,String,String)` from `void AccMgr.setUserDataUnderLock()`] -codetoanalyze/java/starvation/AccMgr.java, void AccMgr.onUiThreadBad(), 20, STARVATION, no_bucket, ERROR, [ `void AccMgr.onUiThreadBad()`,calls `void AccountManager.setUserData(Account,String,String)` from `void AccMgr.onUiThreadBad()`] -codetoanalyze/java/starvation/AsyncTaskGet.java, void AsyncTaskGet.lockOnUiThreadBad(), 31, STARVATION, no_bucket, ERROR, [[Trace 1] `void AsyncTaskGet.lockOnUiThreadBad()`,locks `this.AsyncTaskGet.lock` in class `AsyncTaskGet*`,[Trace 2] `void AsyncTaskGet.taskGetUnderLock()`,locks `this.AsyncTaskGet.lock` in class `AsyncTaskGet*`,calls `Object AsyncTask.get()` from `void AsyncTaskGet.taskGetUnderLock()`] -codetoanalyze/java/starvation/AsyncTaskGet.java, void AsyncTaskGet.taskGetOnUiThreadBad(), 20, STARVATION, no_bucket, ERROR, [ `void AsyncTaskGet.taskGetOnUiThreadBad()`,calls `Object AsyncTask.get()` from `void AsyncTaskGet.taskGetOnUiThreadBad()`] -codetoanalyze/java/starvation/Binders.java, void Binders.annotationBad(), 35, STARVATION, no_bucket, ERROR, [ `void Binders.annotationBad()`,Method call: `void Binders.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void Binders.doTransact()`] -codetoanalyze/java/starvation/Binders.java, void Binders.interBad(), 24, STARVATION, no_bucket, ERROR, [ `void Binders.interBad()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void Binders.interBad()`] -codetoanalyze/java/starvation/Binders.java, void Binders.intraBad(), 30, STARVATION, no_bucket, ERROR, [ `void Binders.intraBad()`,Method call: `void Binders.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void Binders.doTransact()`] -codetoanalyze/java/starvation/Countdwn.java, void Countdwn.awaitOnMainByAnnotBad(), 21, STARVATION, no_bucket, ERROR, [ `void Countdwn.awaitOnMainByAnnotBad()`,calls `void CountDownLatch.await()` from `void Countdwn.awaitOnMainByAnnotBad()`] -codetoanalyze/java/starvation/Countdwn.java, void Countdwn.awaitOnMainByCallBad(), 16, STARVATION, no_bucket, ERROR, [ `void Countdwn.awaitOnMainByCallBad()`,calls `void CountDownLatch.await()` from `void Countdwn.awaitOnMainByCallBad()`] -codetoanalyze/java/starvation/Dedup.java, void Dedup.callMethodWithMultipleBlocksBad(), 26, STARVATION, no_bucket, ERROR, [ `void Dedup.callMethodWithMultipleBlocksBad()`,calls `int InputStreamReader.read()` from `void Dedup.callMethodWithMultipleBlocksBad()`] -codetoanalyze/java/starvation/Dedup.java, void Dedup.callMethodWithMultipleBlocksBad(), 27, STARVATION, no_bucket, ERROR, [ `void Dedup.callMethodWithMultipleBlocksBad()`,calls `void CountDownLatch.await()` from `void Dedup.callMethodWithMultipleBlocksBad()`] -codetoanalyze/java/starvation/Dedup.java, void Dedup.callMethodWithMultipleBlocksBad(), 28, STARVATION, no_bucket, ERROR, [ `void Dedup.callMethodWithMultipleBlocksBad()`,calls `int InputStreamReader.read()` from `void Dedup.callMethodWithMultipleBlocksBad()`] -codetoanalyze/java/starvation/Dedup.java, void Dedup.onUiThreadBad(), 20, STARVATION, no_bucket, ERROR, [ `void Dedup.onUiThreadBad()`,Method call: `void Dedup.callMethodWithMultipleBlocksBad()`,calls `void CountDownLatch.await()` from `void Dedup.callMethodWithMultipleBlocksBad()`] -codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getDirectBad(), 20, STARVATION, no_bucket, ERROR, [ `void FutureGet.getDirectBad()`,calls `Object Future.get()` from `void FutureGet.getDirectBad()`] -codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getIndirectBad(), 25, STARVATION, no_bucket, ERROR, [[Trace 1] `void FutureGet.getIndirectBad()`,locks `this.FutureGet.lock` in class `FutureGet*`,[Trace 2] `void FutureGet.getUnderLock()`,locks `this.FutureGet.lock` in class `FutureGet*`,calls `Object Future.get()` from `void FutureGet.getUnderLock()`] -codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getTimeout50000001MicroSecondsBad(), 76, STARVATION, no_bucket, ERROR, [ `void FutureGet.getTimeout50000001MicroSecondsBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeout50000001MicroSecondsBad()`] -codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getTimeoutOneDayBad(), 41, STARVATION, no_bucket, ERROR, [ `void FutureGet.getTimeoutOneDayBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeoutOneDayBad()`] -codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getTimeoutOneHourBad(), 55, STARVATION, no_bucket, ERROR, [ `void FutureGet.getTimeoutOneHourBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeoutOneHourBad()`] -codetoanalyze/java/starvation/IndirectBlock.java, void IndirectBlock.takeExpensiveLockOnUiThreadBad(), 22, STARVATION, no_bucket, ERROR, [[Trace 1] `void IndirectBlock.takeExpensiveLockOnUiThreadBad()`,locks `this.IndirectBlock.expensiveLock` in class `IndirectBlock*`,[Trace 2] `void IndirectBlock.doTransactUnderLock()`,locks `this.IndirectBlock.expensiveLock` in class `IndirectBlock*`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void IndirectBlock.doTransactUnderLock()`] -codetoanalyze/java/starvation/IndirectBlock.java, void IndirectBlock.takeRemoteExpensiveLockOnUiThreadBad(IndirectInterproc), 33, STARVATION, no_bucket, ERROR, [[Trace 1] `void IndirectBlock.takeRemoteExpensiveLockOnUiThreadBad(IndirectInterproc)`,Method call: `void IndirectInterproc.takeLock()`,locks `this` in class `IndirectInterproc*`,[Trace 2] `void IndirectInterproc.doTransactUnderLock(Binder)`,locks `this` in class `IndirectInterproc*`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void IndirectInterproc.doTransactUnderLock(Binder)`] -codetoanalyze/java/starvation/InnerClass.java, InnerClass$InnerClassA.(InnerClass,Object), 48, DEADLOCK, no_bucket, ERROR, [[Trace 1] `InnerClass$InnerClassA.(InnerClass,Object)`,locks `this` in class `InnerClass$InnerClassA*`,Method call: `void InnerClass.bar()`,locks `this` in class `InnerClass*`,[Trace 2] `void InnerClass.outerInnerBad(InnerClass$InnerClassA)`,locks `this` in class `InnerClass*`,Method call: `void InnerClass$InnerClassA.baz()`,locks `this` in class `InnerClass$InnerClassA*`] -codetoanalyze/java/starvation/InnerClass.java, void InnerClass$InnerClassA.innerOuterBad(), 34, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void InnerClass$InnerClassA.innerOuterBad()`,locks `this` in class `InnerClass$InnerClassA*`,Method call: `void InnerClass.bar()`,locks `this` in class `InnerClass*`,[Trace 2] `void InnerClass.outerInnerBad(InnerClass$InnerClassA)`,locks `this` in class `InnerClass*`,Method call: `void InnerClass$InnerClassA.baz()`,locks `this` in class `InnerClass$InnerClassA*`] -codetoanalyze/java/starvation/Interclass.java, void Interclass.interclass1Bad(InterclassA), 10, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void Interclass.interclass1Bad(InterclassA)`,locks `this` in class `Interclass*`,Method call: `void InterclassA.interclass1Bad()`,locks `this` in class `InterclassA*`,[Trace 2] `void InterclassA.interclass2Bad(Interclass)`,locks `this` in class `InterclassA*`,Method call: `void Interclass.interclass2Bad()`,locks `this` in class `Interclass*`] -codetoanalyze/java/starvation/Interproc.java, void Interproc.interproc1Bad(InterprocA), 9, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void Interproc.interproc1Bad(InterprocA)`,locks `this` in class `Interproc*`,Method call: `void Interproc.interproc2Bad(InterprocA)`,locks `b` in class `InterprocA*`,[Trace 2] `void InterprocA.interproc1Bad(Interproc)`,locks `this` in class `InterprocA*`,Method call: `void InterprocA.interproc2Bad(Interproc)`,locks `d` in class `Interproc*`] -codetoanalyze/java/starvation/Intraproc.java, void Intraproc.intraBad(IntraprocA), 10, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void Intraproc.intraBad(IntraprocA)`,locks `this` in class `Intraproc*`,locks `o` in class `IntraprocA*`,[Trace 2] `void IntraprocA.intraBad(Intraproc)`,locks `this` in class `IntraprocA*`,locks `o` in class `Intraproc*`] -codetoanalyze/java/starvation/JavaIO.java, void JavaIO.fileReadBad(), 31, STARVATION, no_bucket, ERROR, [ `void JavaIO.fileReadBad()`,Method call: `int JavaIO.doFileRead()`,calls `int InputStreamReader.read()` from `int JavaIO.doFileRead()`] -codetoanalyze/java/starvation/JavaIO.java, void JavaIO.streamReadBad(), 36, STARVATION, no_bucket, ERROR, [ `void JavaIO.streamReadBad()`,Method call: `String JavaIO.doStreamRead()`,calls `String DataInputStream.readUTF()` from `String JavaIO.doStreamRead()`] -codetoanalyze/java/starvation/LegacySync.java, Object LegacySync.onUiThreadOpBad(), 25, STARVATION, no_bucket, ERROR, [[Trace 1] `Object LegacySync.onUiThreadOpBad()`,locks `this.LegacySync.table` in class `LegacySync*`,[Trace 2] `void LegacySync.notOnUiThreadSyncedBad()`,locks `this.LegacySync.table` in class `LegacySync*`,calls `Object Future.get()` from `void LegacySync.notOnUiThreadSyncedBad()`] -codetoanalyze/java/starvation/ServiceOnUIThread.java, IBinder ServiceOnUIThread.onBind(Intent), 19, STARVATION, no_bucket, ERROR, [ `IBinder ServiceOnUIThread.onBind(Intent)`,Method call: `void ServiceOnUIThread.transactBad()`,calls `boolean IBinder.transact(int,Parcel,Parcel,int)` from `void ServiceOnUIThread.transactBad()`] -codetoanalyze/java/starvation/ServiceOnUIThread.java, void ServiceOnUIThread.transactBad(), 25, STARVATION, no_bucket, ERROR, [ `void ServiceOnUIThread.transactBad()`,calls `boolean IBinder.transact(int,Parcel,Parcel,int)` from `void ServiceOnUIThread.transactBad()`] -codetoanalyze/java/starvation/StaticLock.java, void StaticLock.lockOtherClassOneWayBad(), 23, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void StaticLock.lockOtherClassOneWayBad()`,locks `StaticLock$0` in class `java.lang.Class*`,locks `this` in class `StaticLock*`,[Trace 2] `void StaticLock.lockOtherClassAnotherWayNad()`,locks `this` in class `StaticLock*`,Method call: `void StaticLock.staticSynced()`,locks `StaticLock$0` in class `java.lang.Class*`] -codetoanalyze/java/starvation/UIDeadlock.java, void UIDeadlock.onUIThreadBad(), 26, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void UIDeadlock.onUIThreadBad()`,locks `this` in class `UIDeadlock*`,locks `this.UIDeadlock.lockB` in class `UIDeadlock*`,[Trace 2] `void UIDeadlock.notOnUIThreadBad()`,locks `this.UIDeadlock.lockB` in class `UIDeadlock*`,locks `this` in class `UIDeadlock*`] -codetoanalyze/java/starvation/VisDispFrame.java, void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad(), 18, STARVATION, no_bucket, ERROR, [ `void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad()`,calls `void View.getWindowVisibleDisplayFrame(Rect)` from `void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad()`] +codetoanalyze/java/starvation/AccMgr.java, void AccMgr.lockOnUiThreadBad(), 25, STARVATION, no_bucket, ERROR, [[Trace 1] `void AccMgr.lockOnUiThreadBad()`,locks `this.AccMgr.lock` in class `AccMgr*`,[Trace 2] `void AccMgr.setUserDataUnderLock()`,locks `this.AccMgr.lock` in class `AccMgr*`,calls `void AccountManager.setUserData(Account,String,String)` from `void AccMgr.setUserDataUnderLock()`] +codetoanalyze/java/starvation/AccMgr.java, void AccMgr.onUiThreadBad(), 20, STARVATION, no_bucket, ERROR, [`void AccMgr.onUiThreadBad()`,calls `void AccountManager.setUserData(Account,String,String)` from `void AccMgr.onUiThreadBad()`] +codetoanalyze/java/starvation/AsyncTaskGet.java, void AsyncTaskGet.lockOnUiThreadBad(), 31, STARVATION, no_bucket, ERROR, [[Trace 1] `void AsyncTaskGet.lockOnUiThreadBad()`,locks `this.AsyncTaskGet.lock` in class `AsyncTaskGet*`,[Trace 2] `void AsyncTaskGet.taskGetUnderLock()`,locks `this.AsyncTaskGet.lock` in class `AsyncTaskGet*`,calls `Object AsyncTask.get()` from `void AsyncTaskGet.taskGetUnderLock()`] +codetoanalyze/java/starvation/AsyncTaskGet.java, void AsyncTaskGet.taskGetOnUiThreadBad(), 20, STARVATION, no_bucket, ERROR, [`void AsyncTaskGet.taskGetOnUiThreadBad()`,calls `Object AsyncTask.get()` from `void AsyncTaskGet.taskGetOnUiThreadBad()`] +codetoanalyze/java/starvation/Binders.java, void Binders.annotationBad(), 35, STARVATION, no_bucket, ERROR, [`void Binders.annotationBad()`,Method call: `void Binders.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void Binders.doTransact()`] +codetoanalyze/java/starvation/Binders.java, void Binders.interBad(), 24, STARVATION, no_bucket, ERROR, [`void Binders.interBad()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void Binders.interBad()`] +codetoanalyze/java/starvation/Binders.java, void Binders.intraBad(), 30, STARVATION, no_bucket, ERROR, [`void Binders.intraBad()`,Method call: `void Binders.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void Binders.doTransact()`] +codetoanalyze/java/starvation/Countdwn.java, void Countdwn.awaitOnMainByAnnotBad(), 21, STARVATION, no_bucket, ERROR, [`void Countdwn.awaitOnMainByAnnotBad()`,calls `void CountDownLatch.await()` from `void Countdwn.awaitOnMainByAnnotBad()`] +codetoanalyze/java/starvation/Countdwn.java, void Countdwn.awaitOnMainByCallBad(), 16, STARVATION, no_bucket, ERROR, [`void Countdwn.awaitOnMainByCallBad()`,calls `void CountDownLatch.await()` from `void Countdwn.awaitOnMainByCallBad()`] +codetoanalyze/java/starvation/Dedup.java, void Dedup.callMethodWithMultipleBlocksBad(), 26, STARVATION, no_bucket, ERROR, [`void Dedup.callMethodWithMultipleBlocksBad()`,calls `int InputStreamReader.read()` from `void Dedup.callMethodWithMultipleBlocksBad()`] +codetoanalyze/java/starvation/Dedup.java, void Dedup.callMethodWithMultipleBlocksBad(), 27, STARVATION, no_bucket, ERROR, [`void Dedup.callMethodWithMultipleBlocksBad()`,calls `void CountDownLatch.await()` from `void Dedup.callMethodWithMultipleBlocksBad()`] +codetoanalyze/java/starvation/Dedup.java, void Dedup.callMethodWithMultipleBlocksBad(), 28, STARVATION, no_bucket, ERROR, [`void Dedup.callMethodWithMultipleBlocksBad()`,calls `int InputStreamReader.read()` from `void Dedup.callMethodWithMultipleBlocksBad()`] +codetoanalyze/java/starvation/Dedup.java, void Dedup.onUiThreadBad(), 20, STARVATION, no_bucket, ERROR, [`void Dedup.onUiThreadBad()`,Method call: `void Dedup.callMethodWithMultipleBlocksBad()`,calls `void CountDownLatch.await()` from `void Dedup.callMethodWithMultipleBlocksBad()`] +codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getDirectBad(), 20, STARVATION, no_bucket, ERROR, [`void FutureGet.getDirectBad()`,calls `Object Future.get()` from `void FutureGet.getDirectBad()`] +codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getIndirectBad(), 25, STARVATION, no_bucket, ERROR, [[Trace 1] `void FutureGet.getIndirectBad()`,locks `this.FutureGet.lock` in class `FutureGet*`,[Trace 2] `void FutureGet.getUnderLock()`,locks `this.FutureGet.lock` in class `FutureGet*`,calls `Object Future.get()` from `void FutureGet.getUnderLock()`] +codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getTimeout50000001MicroSecondsBad(), 76, STARVATION, no_bucket, ERROR, [`void FutureGet.getTimeout50000001MicroSecondsBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeout50000001MicroSecondsBad()`] +codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getTimeoutOneDayBad(), 41, STARVATION, no_bucket, ERROR, [`void FutureGet.getTimeoutOneDayBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeoutOneDayBad()`] +codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getTimeoutOneHourBad(), 55, STARVATION, no_bucket, ERROR, [`void FutureGet.getTimeoutOneHourBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeoutOneHourBad()`] +codetoanalyze/java/starvation/IndirectBlock.java, void IndirectBlock.takeExpensiveLockOnUiThreadBad(), 22, STARVATION, no_bucket, ERROR, [[Trace 1] `void IndirectBlock.takeExpensiveLockOnUiThreadBad()`,locks `this.IndirectBlock.expensiveLock` in class `IndirectBlock*`,[Trace 2] `void IndirectBlock.doTransactUnderLock()`,locks `this.IndirectBlock.expensiveLock` in class `IndirectBlock*`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void IndirectBlock.doTransactUnderLock()`] +codetoanalyze/java/starvation/IndirectBlock.java, void IndirectBlock.takeRemoteExpensiveLockOnUiThreadBad(IndirectInterproc), 33, STARVATION, no_bucket, ERROR, [[Trace 1] `void IndirectBlock.takeRemoteExpensiveLockOnUiThreadBad(IndirectInterproc)`,Method call: `void IndirectInterproc.takeLock()`,locks `this` in class `IndirectInterproc*`,[Trace 2] `void IndirectInterproc.doTransactUnderLock(Binder)`,locks `this` in class `IndirectInterproc*`,calls `boolean Binder.transact(int,Parcel,Parcel,int)` from `void IndirectInterproc.doTransactUnderLock(Binder)`] +codetoanalyze/java/starvation/InnerClass.java, InnerClass$InnerClassA.(InnerClass,Object), 48, DEADLOCK, no_bucket, ERROR, [[Trace 1] `InnerClass$InnerClassA.(InnerClass,Object)`,locks `this` in class `InnerClass$InnerClassA*`,Method call: `void InnerClass.bar()`,locks `this` in class `InnerClass*`,[Trace 2] `void InnerClass.outerInnerBad(InnerClass$InnerClassA)`,locks `this` in class `InnerClass*`,Method call: `void InnerClass$InnerClassA.baz()`,locks `this` in class `InnerClass$InnerClassA*`] +codetoanalyze/java/starvation/InnerClass.java, void InnerClass$InnerClassA.innerOuterBad(), 34, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void InnerClass$InnerClassA.innerOuterBad()`,locks `this` in class `InnerClass$InnerClassA*`,Method call: `void InnerClass.bar()`,locks `this` in class `InnerClass*`,[Trace 2] `void InnerClass.outerInnerBad(InnerClass$InnerClassA)`,locks `this` in class `InnerClass*`,Method call: `void InnerClass$InnerClassA.baz()`,locks `this` in class `InnerClass$InnerClassA*`] +codetoanalyze/java/starvation/Interclass.java, void Interclass.interclass1Bad(InterclassA), 10, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void Interclass.interclass1Bad(InterclassA)`,locks `this` in class `Interclass*`,Method call: `void InterclassA.interclass1Bad()`,locks `this` in class `InterclassA*`,[Trace 2] `void InterclassA.interclass2Bad(Interclass)`,locks `this` in class `InterclassA*`,Method call: `void Interclass.interclass2Bad()`,locks `this` in class `Interclass*`] +codetoanalyze/java/starvation/Interproc.java, void Interproc.interproc1Bad(InterprocA), 9, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void Interproc.interproc1Bad(InterprocA)`,locks `this` in class `Interproc*`,Method call: `void Interproc.interproc2Bad(InterprocA)`,locks `b` in class `InterprocA*`,[Trace 2] `void InterprocA.interproc1Bad(Interproc)`,locks `this` in class `InterprocA*`,Method call: `void InterprocA.interproc2Bad(Interproc)`,locks `d` in class `Interproc*`] +codetoanalyze/java/starvation/Intraproc.java, void Intraproc.intraBad(IntraprocA), 10, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void Intraproc.intraBad(IntraprocA)`,locks `this` in class `Intraproc*`,locks `o` in class `IntraprocA*`,[Trace 2] `void IntraprocA.intraBad(Intraproc)`,locks `this` in class `IntraprocA*`,locks `o` in class `Intraproc*`] +codetoanalyze/java/starvation/JavaIO.java, void JavaIO.fileReadBad(), 31, STARVATION, no_bucket, ERROR, [`void JavaIO.fileReadBad()`,Method call: `int JavaIO.doFileRead()`,calls `int InputStreamReader.read()` from `int JavaIO.doFileRead()`] +codetoanalyze/java/starvation/JavaIO.java, void JavaIO.streamReadBad(), 36, STARVATION, no_bucket, ERROR, [`void JavaIO.streamReadBad()`,Method call: `String JavaIO.doStreamRead()`,calls `String DataInputStream.readUTF()` from `String JavaIO.doStreamRead()`] +codetoanalyze/java/starvation/LegacySync.java, Object LegacySync.onUiThreadOpBad(), 25, STARVATION, no_bucket, ERROR, [[Trace 1] `Object LegacySync.onUiThreadOpBad()`,locks `this.LegacySync.table` in class `LegacySync*`,[Trace 2] `void LegacySync.notOnUiThreadSyncedBad()`,locks `this.LegacySync.table` in class `LegacySync*`,calls `Object Future.get()` from `void LegacySync.notOnUiThreadSyncedBad()`] +codetoanalyze/java/starvation/ServiceOnUIThread.java, IBinder ServiceOnUIThread.onBind(Intent), 19, STARVATION, no_bucket, ERROR, [`IBinder ServiceOnUIThread.onBind(Intent)`,Method call: `void ServiceOnUIThread.transactBad()`,calls `boolean IBinder.transact(int,Parcel,Parcel,int)` from `void ServiceOnUIThread.transactBad()`] +codetoanalyze/java/starvation/ServiceOnUIThread.java, void ServiceOnUIThread.transactBad(), 25, STARVATION, no_bucket, ERROR, [`void ServiceOnUIThread.transactBad()`,calls `boolean IBinder.transact(int,Parcel,Parcel,int)` from `void ServiceOnUIThread.transactBad()`] +codetoanalyze/java/starvation/StaticLock.java, void StaticLock.lockOtherClassOneWayBad(), 23, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void StaticLock.lockOtherClassOneWayBad()`,locks `StaticLock$0` in class `java.lang.Class*`,locks `this` in class `StaticLock*`,[Trace 2] `void StaticLock.lockOtherClassAnotherWayNad()`,locks `this` in class `StaticLock*`,Method call: `void StaticLock.staticSynced()`,locks `StaticLock$0` in class `java.lang.Class*`] +codetoanalyze/java/starvation/UIDeadlock.java, void UIDeadlock.onUIThreadBad(), 26, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void UIDeadlock.onUIThreadBad()`,locks `this` in class `UIDeadlock*`,locks `this.UIDeadlock.lockB` in class `UIDeadlock*`,[Trace 2] `void UIDeadlock.notOnUIThreadBad()`,locks `this.UIDeadlock.lockB` in class `UIDeadlock*`,locks `this` in class `UIDeadlock*`] +codetoanalyze/java/starvation/VisDispFrame.java, void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad(), 18, STARVATION, no_bucket, ERROR, [`void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad()`,calls `void View.getWindowVisibleDisplayFrame(Rect)` from `void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad()`]