[starvation] explain why we think a method runs on the ui thread

Summary: Track and surface the reasons why a method is assessed to run on the UI thread.

Reviewed By: mbouaziz

Differential Revision: D8096099

fbshipit-source-id: 2403c6c
master
Nikos Gorogiannis 7 years ago committed by Facebook Github Bot
parent 4a710a64b1
commit e36ca3d07f

@ -157,7 +157,7 @@ module Pair (Domain1 : S) (Domain2 : S) = struct
, Domain2.widen ~prev:(snd prev) ~next:(snd next) ~num_iters )
let pp fmt (astate1, astate2) = F.fprintf fmt "(%a, %a)" Domain1.pp astate1 Domain2.pp astate2
let pp fmt astate = Pp.pair ~fst:Domain1.pp ~snd:Domain2.pp fmt astate
end
module FiniteSetOfPPSet (S : PrettyPrintable.PPSet) = struct

@ -276,35 +276,40 @@ let proc_calls resolve_attributes pdesc filter : (Typ.Procname.t * ProcAttribute
List.rev !res
let override_exists ?(check_current_type= true) f tenv proc_name =
let override_find ?(check_current_type= true) f tenv proc_name =
let method_name = Typ.Procname.get_method proc_name in
let rec super_type_exists_ tenv super_class_name =
match Tenv.lookup tenv super_class_name with
| Some {methods; supers} ->
let is_override pname =
(* Note: very coarse! TODO: match parameter names/types to get an exact match *)
String.equal (Typ.Procname.get_method pname) method_name
&& not (Typ.Procname.is_constructor pname)
in
List.exists ~f:(fun pname -> is_override pname && f pname) methods
|| List.exists ~f:(super_type_exists_ tenv) supers
| _ ->
false
let rec find_super_type_ super_class_name =
Tenv.lookup tenv super_class_name
|> Option.bind ~f:(fun {Typ.Struct.methods; supers} ->
match List.find ~f:(fun pname -> is_override pname && f pname) methods with
| None ->
List.find_map ~f:find_super_type_ supers
| pname_opt ->
pname_opt )
in
let super_type_exists tenv type_name =
List.exists ~f:(super_type_exists_ tenv)
let find_super_type type_name =
List.find_map ~f:find_super_type_
(type_get_direct_supertypes tenv (Typ.mk (Tstruct type_name)))
in
(check_current_type && f proc_name)
||
if check_current_type && f proc_name then Some proc_name
else
match proc_name with
| Typ.Procname.Java proc_name_java ->
super_type_exists tenv
find_super_type
(Typ.Name.Java.from_string (Typ.Procname.Java.get_class_name proc_name_java))
| Typ.Procname.ObjC_Cpp proc_name_cpp ->
super_type_exists tenv (Typ.Procname.ObjC_Cpp.get_class_type_name proc_name_cpp)
find_super_type (Typ.Procname.ObjC_Cpp.get_class_type_name proc_name_cpp)
| _ ->
false
None
let override_exists ?(check_current_type= true) f tenv proc_name =
override_find ~check_current_type f tenv proc_name |> Option.is_some
(* Only java supported at the moment *)

@ -50,6 +50,11 @@ val proc_calls :
-> (Typ.Procname.t -> ProcAttributes.t -> bool) -> (Typ.Procname.t * ProcAttributes.t) list
(** Return the callees that satisfy [filter]. *)
val override_find :
?check_current_type:bool -> (Typ.Procname.t -> bool) -> Tenv.t -> Typ.Procname.t
-> Typ.Procname.t option
(** Return a method which overrides [procname] and satisfies [f] (including [procname] itself when [check_current_type] is true, which it is by default). *)
val override_exists :
?check_current_type:bool -> (Typ.Procname.t -> bool) -> Tenv.t -> Typ.Procname.t -> bool
(** Return true if applying the given predicate to an override of [procname] (including [procname] itself when [check_current_type] is true, which it is by default) returns true. *)

@ -672,7 +672,7 @@ let analyze_procedure {Callbacks.proc_desc; get_proc_desc; tenv; summary} =
let initial =
let threads =
if
Models.runs_on_ui_thread tenv proc_desc
Models.runs_on_ui_thread tenv proc_desc |> Option.is_some
|| Models.is_thread_confined_method tenv proc_desc
then ThreadsDomain.AnyThreadButSelf
else if

@ -10,6 +10,7 @@
open! IStd
module F = Format
module L = Logging
module MF = MarkupFormatter
module AnnotationAliases = struct
let of_json = function
@ -494,8 +495,8 @@ module Models = struct
None
let is_annotated_or_overriden_annotated_method is_annot pname tenv =
PatternMatch.override_exists
let find_annotated_or_overriden_annotated_method is_annot pname tenv =
PatternMatch.override_find
(fun pn ->
Annotations.pname_has_return_annot pn ~attrs_of_pname:Summary.proc_resolve_attributes
is_annot )
@ -513,17 +514,42 @@ module Models = struct
|| Annotations.ia_is_on_unbind annot || Annotations.ia_is_on_unmount annot
in
let pname = Procdesc.get_proc_name proc_desc in
Annotations.pdesc_has_return_annot proc_desc is_annot
|| is_annotated_or_overriden_annotated_method is_annot pname tenv
||
match get_current_class_and_annotated_superclasses Annotations.ia_is_ui_thread tenv pname with
| Some (_, _ :: _) ->
true
| Some (current_class, _) ->
PatternMatch.is_subtype_of_str tenv current_class "android.app.Service"
&& not (PatternMatch.is_subtype_of_str tenv current_class "android.app.IntentService")
if Annotations.pdesc_has_return_annot proc_desc is_annot then
Some
(F.asprintf "%a is annotated %s"
(MF.wrap_monospaced Typ.Procname.pp)
pname
(MF.monospaced_to_string Annotations.ui_thread))
else
match find_annotated_or_overriden_annotated_method is_annot pname tenv with
| Some override_pname ->
Some
(F.asprintf "class %a overrides %a, which is annotated %s"
(MF.wrap_monospaced Typ.Procname.pp)
pname
(MF.wrap_monospaced Typ.Procname.pp)
override_pname
(MF.monospaced_to_string Annotations.ui_thread))
| None ->
match
get_current_class_and_annotated_superclasses Annotations.ia_is_ui_thread tenv pname
with
| Some (current_class, _)
when let open PatternMatch in
is_subtype_of_str tenv current_class "android.app.Service"
&& not (is_subtype_of_str tenv current_class "android.app.IntentService") ->
Some
(F.asprintf "class %s extends %s"
(MF.monospaced_to_string (Typ.Name.name current_class))
(MF.monospaced_to_string "android.app.Service"))
| Some (current_class, super_class :: _) ->
Some
(F.asprintf "class %s extends %a, which is annotated %s"
(MF.monospaced_to_string (Typ.Name.name current_class))
(MF.wrap_monospaced Typ.Name.pp) super_class
(MF.monospaced_to_string Annotations.ui_thread))
| _ ->
false
None
let get_current_class_and_threadsafe_superclasses tenv pname =
@ -544,7 +570,7 @@ module Models = struct
let is_thread_safe_method pname tenv =
is_annotated_or_overriden_annotated_method is_thread_safe pname tenv
find_annotated_or_overriden_annotated_method is_thread_safe pname tenv |> Option.is_some
let is_marked_thread_safe pdesc tenv =

@ -54,11 +54,12 @@ module Models : sig
completely different classes that don't necessarily run on the same thread as the confined
object. *)
val runs_on_ui_thread : Tenv.t -> Procdesc.t -> bool
val runs_on_ui_thread : Tenv.t -> Procdesc.t -> string option
(** We don't want to warn on methods that run on the UI thread because they should always be
single-threaded. Assume that methods annotated with @UiThread, @OnEvent, @OnBind, @OnMount,
@OnUnbind, @OnUnmount always run on the UI thread. Also assume that any superclass
marked @UiThread implies all methods are on UI thread. *)
marked @UiThread implies all methods are on UI thread. Return Some string explaining why
this method is on the UI thread, else return None. *)
val should_analyze_proc : Procdesc.t -> Tenv.t -> bool
(** return true if we should compute a summary for the procedure. if this returns false, we won't

@ -13,7 +13,7 @@ module MF = MarkupFormatter
let debug fmt = L.(debug Analysis Verbose fmt)
let is_on_main_thread pn =
let is_on_ui_thread pn =
RacerDConfig.(match Models.get_thread pn with Models.MainThread -> true | _ -> false)
@ -81,8 +81,9 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| NoEffect when Models.may_block tenv callee actuals ->
let caller = Procdesc.get_proc_name pdesc in
Domain.blocking_call ~caller ~callee loc astate
| NoEffect when is_on_main_thread callee ->
Domain.set_on_main_thread astate
| NoEffect when is_on_ui_thread callee ->
let explanation = F.asprintf "calls %a" (MF.wrap_monospaced Typ.Procname.pp) callee in
Domain.set_on_ui_thread astate explanation
| _ ->
Payload.read pdesc callee
|> Option.value_map ~default:astate ~f:(Domain.integrate_summary astate callee loc) )
@ -124,9 +125,8 @@ let analyze_procedure {Callbacks.proc_desc; tenv; summary} =
~f:(StarvationDomain.acquire StarvationDomain.empty loc)
in
let initial =
if RacerDConfig.Models.runs_on_ui_thread tenv proc_desc then
StarvationDomain.set_on_main_thread initial
else initial
RacerDConfig.Models.runs_on_ui_thread tenv proc_desc
|> Option.value_map ~default:initial ~f:(StarvationDomain.set_on_ui_thread initial)
in
Analyzer.compute_post proc_data ~initial
|> Option.value_map ~default:summary ~f:(fun lock_state ->
@ -244,13 +244,13 @@ let report_deadlocks tenv current_pdesc (summary, current_main) =
let endpoint_summaries = get_summaries_of_methods_in_class tenv endpoint_class in
(* for each summary related to the endpoint, analyse and report on its pairs *)
List.iter endpoint_summaries ~f:(fun (endpoint_pname, (summary, endpoint_main)) ->
if not (current_main && endpoint_main) then
if UIThreadDomain.is_empty current_main || UIThreadDomain.is_empty endpoint_main then
LockOrderDomain.iter (report_endpoint_elem elem endpoint_pname) summary )
in
LockOrderDomain.iter report_on_current_elem summary
let report_blocks_on_main_thread tenv current_pdesc summary =
let report_blocks_on_main_thread tenv current_pdesc order ui_explain =
let open StarvationDomain in
let current_loc = Procdesc.get_loc current_pdesc in
let current_pname = Procdesc.get_proc_name current_pdesc in
@ -260,9 +260,11 @@ let report_blocks_on_main_thread tenv current_pdesc summary =
; eventually= {LockEvent.event= LockEvent.MayBlock block_descr} }
when LockIdentity.equal current_lock lock ->
let error_message =
Format.asprintf "UI thread method %a %a, which may be held by another thread which %s"
Format.asprintf
"Method %a runs on UI thread (because %s) and %a, which may be held by another thread \
which %s"
(MF.wrap_monospaced Typ.Procname.pp)
current_pname LockIdentity.pp lock block_descr
current_pname ui_explain LockIdentity.pp lock block_descr
in
let exn =
Exceptions.Checkers (IssueType.starvation, Localise.verbatim_desc error_message)
@ -278,9 +280,9 @@ let report_blocks_on_main_thread tenv current_pdesc summary =
match eventually with
| {LockEvent.event= LockEvent.MayBlock _} ->
let error_message =
Format.asprintf "UI thread method %a may block; %a"
Format.asprintf "Method %a runs on UI thread (because %s), and may block; %a"
(MF.wrap_monospaced Typ.Procname.pp)
current_pname LockEvent.pp_event eventually.LockEvent.event
current_pname ui_explain LockEvent.pp_event eventually.LockEvent.event
in
let exn =
Exceptions.Checkers (IssueType.starvation, Localise.verbatim_desc error_message)
@ -296,24 +298,26 @@ let report_blocks_on_main_thread tenv current_pdesc summary =
and retrieve all the summaries of the methods of that class *)
let endpoint_summaries = get_summaries_of_methods_in_class tenv endpoint_class in
(* for each summary related to the endpoint, analyse and report on its pairs *)
List.iter endpoint_summaries ~f:(fun (endpoint_pname, (summary, main)) ->
List.iter endpoint_summaries ~f:(fun (endpoint_pname, (order, ui)) ->
(* skip methods known to run on ui thread, as they cannot run in parallel to us *)
if main then ()
else
LockOrderDomain.iter
(report_remote_block elem endpoint_lock endpoint_pname)
summary )
if UIThreadDomain.is_empty ui then
LockOrderDomain.iter (report_remote_block elem endpoint_lock endpoint_pname) order
)
in
LockOrderDomain.iter report_on_current_elem summary
LockOrderDomain.iter report_on_current_elem order
let reporting {Callbacks.procedures; exe_env} =
let report_procedure (tenv, proc_desc) =
die_if_not_java proc_desc ;
Payload.read proc_desc (Procdesc.get_proc_name proc_desc)
|> Option.iter ~f:(fun ((s, main) as summary) ->
|> Option.iter ~f:(fun ((order, ui) as summary) ->
report_deadlocks tenv proc_desc summary ;
if main then report_blocks_on_main_thread tenv proc_desc s )
match ui with
| AbstractDomain.Types.Bottom ->
()
| AbstractDomain.Types.NonBottom on_ui ->
report_blocks_on_main_thread tenv proc_desc order on_ui )
in
List.iter procedures ~f:report_procedure ;
let sourcefile = exe_env.Exe_env.source_file in

@ -9,6 +9,7 @@
open! IStd
module F = Format
module L = Logging
module MF = MarkupFormatter
module LockIdentity = struct
type t = AccessPath.t
@ -41,7 +42,11 @@ module LockIdentity = struct
let pp fmt (((_, typ), _) as lock) =
F.fprintf fmt "locks `%a` in class `%a`" AccessPath.pp lock (Typ.pp_full Pp.text) typ
F.fprintf fmt "locks %a in class %a"
(MF.wrap_monospaced AccessPath.pp)
lock
(MF.wrap_monospaced (Typ.pp_full Pp.text))
typ
let owner_class ((_, typ), _) = Typ.inner_name typ
@ -100,7 +105,13 @@ module LockEvent = struct
let make_blocks msg loc = {event= MayBlock msg; loc; trace= []}
let make_blocking_call ~caller ~callee loc =
let descr = F.asprintf "calls %a from %a" Typ.Procname.pp callee Typ.Procname.pp caller in
let descr =
F.asprintf "calls %a from %a"
(MF.wrap_monospaced Typ.Procname.pp)
callee
(MF.wrap_monospaced Typ.Procname.pp)
caller
in
make_blocks descr loc
@ -108,7 +119,9 @@ module LockEvent = struct
let call_trace, nesting =
List.fold e.trace ~init:([], 0) ~f:(fun (tr, ns) callsite ->
let elem_descr =
F.asprintf "Method call: %a" Typ.Procname.pp (CallSite.pname callsite)
F.asprintf "Method call: %a"
(MF.wrap_monospaced Typ.Procname.pp)
(CallSite.pname callsite)
in
let elem = Errlog.make_trace_element ns (CallSite.loc callsite) elem_descr [] in
(elem :: tr, ns + 1) )
@ -204,13 +217,25 @@ module LockState = struct
fold ff map init
end
module MainThreadDomain = AbstractDomain.BooleanOr
include AbstractDomain.Pair (AbstractDomain.Pair (LockState) (LockOrderDomain)) (MainThreadDomain)
module UIThreadExplanationDomain = struct
type astate = string
let pp = String.pp
let join lhs _ = lhs
let widen ~prev ~next ~num_iters:_ = join prev next
let ( <= ) ~lhs:_ ~rhs:_ = true
end
module UIThreadDomain = AbstractDomain.BottomLifted (UIThreadExplanationDomain)
include AbstractDomain.Pair (AbstractDomain.Pair (LockState) (LockOrderDomain)) (UIThreadDomain)
let empty = ((LockState.empty, LockOrderDomain.empty), false)
let empty = ((LockState.empty, LockOrderDomain.empty), UIThreadDomain.empty)
let is_empty ((ls, lo), main) =
LockState.is_empty ls && LockOrderDomain.is_empty lo && MainThreadDomain.is_empty main
LockState.is_empty ls && LockOrderDomain.is_empty lo && UIThreadDomain.is_empty main
(* for every lock b held locally, add a pair (b, lock_event), plus (None, lock_event) *)
@ -260,15 +285,17 @@ let integrate_summary ((ls, lo), main) callee_pname loc callee_summary =
(* add callsite to the "eventually" trace *)
let elems = LockOrderDomain.with_callsite callsite callee_lo in
let lo' = LockOrderDomain.fold do_elem elems lo in
let main' = MainThreadDomain.join main callee_main in
let main' = UIThreadDomain.join main callee_main in
((ls, lo'), main')
let set_on_main_thread (sum, _) = (sum, true)
let set_on_ui_thread (sum, explain_opt) explain =
(sum, UIThreadDomain.join explain_opt (AbstractDomain.Types.NonBottom explain))
let to_summary ((_, lo), main) = (lo, main)
type summary = LockOrderDomain.astate * MainThreadDomain.astate
type summary = LockOrderDomain.astate * UIThreadDomain.astate
let pp_summary fmt (lo, main) =
F.fprintf fmt "LockOrder: %a, MainThread: %a" LockOrderDomain.pp lo MainThreadDomain.pp main
F.fprintf fmt "LockOrder: %a, UIThread: %a" LockOrderDomain.pp lo UIThreadDomain.pp main

@ -55,6 +55,9 @@ module LockOrderDomain : sig
include AbstractDomain.WithBottom with type astate = t
end
module UIThreadDomain :
AbstractDomain.WithBottom with type astate = string AbstractDomain.Types.bottom_lifted
include AbstractDomain.WithBottom
val acquire : astate -> Location.t -> LockIdentity.t -> astate
@ -64,9 +67,11 @@ val release : astate -> LockIdentity.t -> astate
val blocking_call :
caller:Typ.Procname.t -> callee:Typ.Procname.t -> Location.t -> astate -> astate
val set_on_main_thread : astate -> astate
val set_on_ui_thread : astate -> string -> astate
(** set the property "runs on UI thread" to true by attaching the given explanation string as to
why this method is thought to do so *)
type summary = LockOrderDomain.astate * bool
type summary = LockOrderDomain.astate * UIThreadDomain.astate
val pp_summary : F.formatter -> summary -> unit

@ -1,29 +1,29 @@
codetoanalyze/java/starvation/AccMgr.java, void AccMgr.lockOnUiThreadBad(), 26, STARVATION, 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(), 21, STARVATION, ERROR, [ `void AccMgr.onUiThreadBad()`,calls void AccountManager.setUserData(Account,String,String) from void AccMgr.onUiThreadBad()]
codetoanalyze/java/starvation/AsyncTaskGet.java, void AsyncTaskGet.lockOnUiThreadBad(), 32, STARVATION, 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(), 21, STARVATION, ERROR, [ `void AsyncTaskGet.taskGetOnUiThreadBad()`,calls Object AsyncTask.get() from void AsyncTaskGet.taskGetOnUiThreadBad()]
codetoanalyze/java/starvation/Binders.java, void Binders.annotationBad(), 36, STARVATION, 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(), 25, STARVATION, 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, 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(), 22, STARVATION, ERROR, [ `void Countdwn.awaitOnMainByAnnotBad()`,calls void CountDownLatch.await() from void Countdwn.awaitOnMainByAnnotBad()]
codetoanalyze/java/starvation/Countdwn.java, void Countdwn.awaitOnMainByCallBad(), 16, STARVATION, ERROR, [ `void Countdwn.awaitOnMainByCallBad()`,calls void CountDownLatch.await() from void Countdwn.awaitOnMainByCallBad()]
codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getDirectBad(), 21, STARVATION, ERROR, [ `void FutureGet.getDirectBad()`,calls Object Future.get() from void FutureGet.getDirectBad()]
codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getIndirectBad(), 26, STARVATION, 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, ERROR, [ `void FutureGet.getTimeout50000001MicroSecondsBad()`,calls Object Future.get(long,TimeUnit) from void FutureGet.getTimeout50000001MicroSecondsBad()]
codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getTimeoutOneDayBad(), 41, STARVATION, ERROR, [ `void FutureGet.getTimeoutOneDayBad()`,calls Object Future.get(long,TimeUnit) from void FutureGet.getTimeoutOneDayBad()]
codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getTimeoutOneHourBad(), 55, STARVATION, ERROR, [ `void FutureGet.getTimeoutOneHourBad()`,calls Object Future.get(long,TimeUnit) from void FutureGet.getTimeoutOneHourBad()]
codetoanalyze/java/starvation/IndirectBlock.java, void IndirectBlock.takeExpensiveLockOnUiThreadBad(), 23, STARVATION, 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), 34, STARVATION, 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.<init>(InnerClass,Object), 49, DEADLOCK, ERROR, [[Trace 1] `InnerClass$InnerClassA.<init>(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(), 36, DEADLOCK, 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), 12, DEADLOCK, 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), 11, DEADLOCK, 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/AccMgr.java, void AccMgr.lockOnUiThreadBad(), 26, STARVATION, 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(), 21, STARVATION, ERROR, [ `void AccMgr.onUiThreadBad()`,calls `void AccountManager.setUserData(Account,String,String)` from `void AccMgr.onUiThreadBad()`]
codetoanalyze/java/starvation/AsyncTaskGet.java, void AsyncTaskGet.lockOnUiThreadBad(), 32, STARVATION, 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(), 21, STARVATION, ERROR, [ `void AsyncTaskGet.taskGetOnUiThreadBad()`,calls `Object AsyncTask.get()` from `void AsyncTaskGet.taskGetOnUiThreadBad()`]
codetoanalyze/java/starvation/Binders.java, void Binders.annotationBad(), 36, STARVATION, 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(), 25, STARVATION, 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, 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(), 22, STARVATION, ERROR, [ `void Countdwn.awaitOnMainByAnnotBad()`,calls `void CountDownLatch.await()` from `void Countdwn.awaitOnMainByAnnotBad()`]
codetoanalyze/java/starvation/Countdwn.java, void Countdwn.awaitOnMainByCallBad(), 16, STARVATION, ERROR, [ `void Countdwn.awaitOnMainByCallBad()`,calls `void CountDownLatch.await()` from `void Countdwn.awaitOnMainByCallBad()`]
codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getDirectBad(), 21, STARVATION, ERROR, [ `void FutureGet.getDirectBad()`,calls `Object Future.get()` from `void FutureGet.getDirectBad()`]
codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getIndirectBad(), 26, STARVATION, 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, ERROR, [ `void FutureGet.getTimeout50000001MicroSecondsBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeout50000001MicroSecondsBad()`]
codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getTimeoutOneDayBad(), 41, STARVATION, ERROR, [ `void FutureGet.getTimeoutOneDayBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeoutOneDayBad()`]
codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getTimeoutOneHourBad(), 55, STARVATION, ERROR, [ `void FutureGet.getTimeoutOneHourBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeoutOneHourBad()`]
codetoanalyze/java/starvation/IndirectBlock.java, void IndirectBlock.takeExpensiveLockOnUiThreadBad(), 23, STARVATION, 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), 34, STARVATION, 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.<init>(InnerClass,Object), 49, DEADLOCK, ERROR, [[Trace 1] `InnerClass$InnerClassA.<init>(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(), 36, DEADLOCK, 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), 12, DEADLOCK, 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), 11, DEADLOCK, 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), 11, DEADLOCK, 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(), 32, STARVATION, 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(), 37, STARVATION, 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(), 26, STARVATION, 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), 20, STARVATION, 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, ERROR, [ `void ServiceOnUIThread.transactBad()`,calls boolean IBinder.transact(int,Parcel,Parcel,int) from void ServiceOnUIThread.transactBad()]
codetoanalyze/java/starvation/StaticLock.java, void StaticLock.lockOtherClassOneWayBad(), 24, DEADLOCK, 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/JavaIO.java, void JavaIO.fileReadBad(), 32, STARVATION, 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(), 37, STARVATION, 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(), 26, STARVATION, 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), 20, STARVATION, 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, ERROR, [ `void ServiceOnUIThread.transactBad()`,calls `boolean IBinder.transact(int,Parcel,Parcel,int)` from `void ServiceOnUIThread.transactBad()`]
codetoanalyze/java/starvation/StaticLock.java, void StaticLock.lockOtherClassOneWayBad(), 24, DEADLOCK, 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(), 28, DEADLOCK, 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(), 19, STARVATION, ERROR, [ `void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad()`,calls void View.getWindowVisibleDisplayFrame(Rect) from void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad()]
codetoanalyze/java/starvation/VisDispFrame.java, void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad(), 19, STARVATION, ERROR, [ `void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad()`,calls `void View.getWindowVisibleDisplayFrame(Rect)` from `void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad()`]

Loading…
Cancel
Save