[starvation] deduplication

Summary:
There can be multiple reports per line, especially when calling in a method which has itself multiple reports.

When reporting at the callsite, report only the issue with the highest severity (picked manually per type of event).

Deadlocks are not de-duplicated, as they are relatively rare and the info in mupltiple reports may be important.

Reviewed By: mbouaziz

Differential Revision: D8160940

fbshipit-source-id: ea6a5c0
master
Nikos Gorogiannis 7 years ago committed by Facebook Github Bot
parent 3400e80122
commit c70b978aa8

@ -700,17 +700,20 @@ module Models = struct
["android.os.AsyncTask"] "get"
(* at most one function is allowed to be true *)
let may_block =
let open StarvationDomain.LockEvent in
let matchers =
[ is_blocking_java_io
; is_countdownlatch_await
; is_two_way_binder_transact
; is_getWindowVisibleDisplayFrame
; is_future_get
; is_accountManager_setUserData
; is_asyncTask_get ]
[ (is_blocking_java_io, Low)
; (is_countdownlatch_await, Medium)
; (is_two_way_binder_transact, High)
; (is_getWindowVisibleDisplayFrame, Low)
; (is_future_get, High)
; (is_accountManager_setUserData, High)
; (is_asyncTask_get, High) ]
in
fun tenv pn actuals -> List.exists matchers ~f:(fun matcher -> matcher tenv pn actuals)
fun tenv pn actuals ->
List.find_map matchers ~f:(fun (matcher, sev) -> Option.some_if (matcher tenv pn actuals) sev)
let is_synchronized_library_call =

@ -81,7 +81,8 @@ module Models : sig
(** return true if procedure is at an abstraction boundary or reporting has been explicitly
requested via @ThreadSafe *)
val may_block : Tenv.t -> Typ.Procname.t -> HilExp.t list -> bool
val may_block :
Tenv.t -> Typ.Procname.t -> HilExp.t list -> StarvationDomain.LockEvent.severity_t option
(** is the method call potentially blocking, given the actuals passed? *)
val is_synchronized_library_call : Tenv.t -> Typ.Procname.t -> bool

@ -78,15 +78,17 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| NoEffect when Models.is_synchronized_library_call tenv callee ->
(* model a synchronized call without visible internal behaviour *)
do_lock actuals loc astate |> do_unlock actuals
| 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_ui_thread callee ->
let explanation = F.asprintf "calls %a" (MF.wrap_monospaced Typ.Procname.pp) callee in
let explanation = F.asprintf "it 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) )
| NoEffect ->
match Models.may_block tenv callee actuals with
| Some sev ->
let caller = Procdesc.get_proc_name pdesc in
Domain.blocking_call ~caller ~callee sev loc astate
| None ->
Payload.read pdesc callee
|> Option.value_map ~default:astate ~f:(Domain.integrate_summary astate callee loc) )
| _ ->
astate
@ -159,9 +161,64 @@ let get_summaries_of_methods_in_class tenv clazz =
(Summary.get_proc_name sum, p) ) )
let log_issue current_pname current_loc ltr exn =
Reporting.log_issue_external current_pname Exceptions.Kerror ~loc:current_loc ~ltr exn
(** per-procedure report map, which takes care of deduplication *)
module ReportMap = struct
type issue_t = Starvation of StarvationDomain.LockEvent.severity_t | Deadlock
[@@deriving compare]
type report_t =
{ issue: issue_t
; pname: Typ.Procname.t [@compare.ignore]
; ltr: Errlog.loc_trace [@compare.ignore]
; message: string [@compare.ignore] }
[@@deriving compare]
module LocMap = PrettyPrintable.MakePPMap (Location)
let empty : report_t list LocMap.t = LocMap.empty
let add issue pname loc ltr message map =
let rep = {issue; pname; ltr; message} in
let preexisting = try LocMap.find loc map with Caml.Not_found -> [] in
LocMap.add loc (rep :: preexisting) map
let add_deadlock pname loc ltr exn map = add Deadlock pname loc ltr exn map
let add_starvation sev pname loc ltr exn map = add (Starvation sev) pname loc ltr exn map
let log map =
let log_report loc {issue; pname; ltr; message} =
let issue_type =
match issue with Deadlock -> IssueType.deadlock | Starvation _ -> IssueType.starvation
in
let exn = Exceptions.Checkers (issue_type, Localise.verbatim_desc message) in
Reporting.log_issue_external pname Exceptions.Kerror ~loc ~ltr exn
in
let mk_deduped_report num_of_reports ({message} as report) =
{ report with
message=
Printf.sprintf "%s %d more starvation report(s) on the same line suppressed." message
(num_of_reports - 1) }
in
let log_location loc reports =
let deadlocks, starvations =
List.partition_tf ~f:(function {issue= Deadlock} -> true | _ -> false) reports
in
(* report all deadlocks *)
List.iter ~f:(log_report loc) deadlocks ;
match starvations with
| [] ->
()
| [report] ->
log_report loc report
| _ ->
List.max_elt ~compare:compare_report_t starvations
|> Option.iter ~f:(fun rep ->
mk_deduped_report (List.length starvations) rep |> log_report loc )
in
LocMap.iter log_location map
end
let should_report_deadlock_on_current_proc current_elem endpoint_elem =
let open StarvationDomain in
@ -200,15 +257,16 @@ let should_report_deadlock_on_current_proc current_elem endpoint_elem =
inner class but this is no longer obvious in the path, because of nested-class path normalisation.
The net effect of the above issues is that we will only see these locks in conflicting pairs
once, as opposed to twice with all other deadlock pairs. *)
let report_deadlocks tenv current_pdesc (summary, current_main) =
let report_deadlocks tenv current_pdesc (summary, current_main) report_map' =
let open StarvationDomain in
let current_loc = Procdesc.get_loc current_pdesc in
let current_pname = Procdesc.get_proc_name current_pdesc in
let report_endpoint_elem current_elem endpoint_pname elem =
let report_endpoint_elem current_elem endpoint_pname elem report_map =
if
LockOrder.may_deadlock current_elem elem
&& should_report_deadlock_on_current_proc current_elem elem
then
not
( LockOrder.may_deadlock current_elem elem
&& should_report_deadlock_on_current_proc current_elem elem )
then report_map
else
let () = debug "Possible deadlock:@.%a@.%a@." LockOrder.pp current_elem LockOrder.pp elem in
match (current_elem.LockOrder.eventually, elem.LockOrder.eventually) with
| {LockEvent.event= LockAcquire _}, {LockEvent.event= LockAcquire _} ->
@ -220,104 +278,99 @@ let report_deadlocks tenv current_pdesc (summary, current_main) =
(MF.wrap_monospaced Typ.Procname.pp)
endpoint_pname LockOrder.pp elem
in
let exn =
Exceptions.Checkers (IssueType.deadlock, Localise.verbatim_desc error_message)
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
log_issue current_pname current_loc ltr exn
let loc = LockOrder.get_loc current_elem in
ReportMap.add_deadlock current_pname loc ltr error_message report_map
| _, _ ->
()
report_map
in
let report_on_current_elem elem =
let report_on_current_elem elem report_map =
match elem with
| {LockOrder.first= None} | {LockOrder.eventually= {LockEvent.event= LockEvent.MayBlock _}} ->
()
report_map
| {LockOrder.eventually= {LockEvent.event= LockEvent.LockAcquire endpoint_lock}} ->
match LockIdentity.owner_class endpoint_lock with
| None ->
()
| Some endpoint_class ->
(* get the class of the root variable of the lock in the endpoint event
LockIdentity.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 event
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, endpoint_main)) ->
if UIThreadDomain.is_empty current_main || UIThreadDomain.is_empty endpoint_main then
LockOrderDomain.iter (report_endpoint_elem elem endpoint_pname) summary )
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.fold endpoint_summaries ~init:report_map ~f:
(fun acc (endp_pname, (endp_summary, endp_ui)) ->
if UIThreadDomain.is_empty current_main || UIThreadDomain.is_empty endp_ui then
LockOrderDomain.fold (report_endpoint_elem elem endp_pname) endp_summary acc
else acc ) )
in
LockOrderDomain.iter report_on_current_elem summary
LockOrderDomain.fold report_on_current_elem summary report_map'
let report_blocks_on_main_thread tenv current_pdesc order ui_explain =
let report_blocks_on_main_thread tenv current_pdesc (order, ui) report_map' =
let open StarvationDomain in
let current_loc = Procdesc.get_loc current_pdesc in
let current_pname = Procdesc.get_proc_name current_pdesc in
let report_remote_block current_elem current_lock endpoint_pname endpoint_elem =
let report_remote_block ui_explain current_elem current_lock endpoint_pname endpoint_elem
report_map =
match endpoint_elem with
| { LockOrder.first= Some {LockEvent.event= LockEvent.LockAcquire lock}
; eventually= {LockEvent.event= LockEvent.MayBlock block_descr} }
; eventually= {LockEvent.event= LockEvent.MayBlock (block_descr, sev)} }
when LockIdentity.equal current_lock lock ->
let error_message =
Format.asprintf
"Method %a runs on UI thread (because %s) and %a, which may be held by another thread \
which %s"
which %s."
(MF.wrap_monospaced Typ.Procname.pp)
current_pname ui_explain LockIdentity.pp lock block_descr
in
let exn =
Exceptions.Checkers (IssueType.starvation, Localise.verbatim_desc error_message)
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
log_issue current_pname current_loc ltr exn
let loc = LockOrder.get_loc current_elem in
ReportMap.add_starvation sev current_pname loc ltr error_message report_map
| _ ->
()
report_map
in
let report_on_current_elem ({LockOrder.eventually} as elem) =
let report_on_current_elem ui_explain ({LockOrder.eventually} as elem) report_map =
match eventually with
| {LockEvent.event= LockEvent.MayBlock _} ->
| {LockEvent.event= LockEvent.MayBlock (_, sev)} ->
let error_message =
Format.asprintf "Method %a runs on UI thread (because %s), and 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 ui_explain LockEvent.pp_event eventually.LockEvent.event
in
let exn =
Exceptions.Checkers (IssueType.starvation, Localise.verbatim_desc error_message)
in
let loc = LockOrder.get_loc elem in
let ltr = make_trace_with_header elem current_pname in
log_issue current_pname current_loc ltr exn
ReportMap.add_starvation sev current_pname loc ltr error_message report_map
| {LockEvent.event= LockEvent.LockAcquire endpoint_lock} ->
match LockIdentity.owner_class endpoint_lock with
| None ->
()
| Some endpoint_class ->
(* get the class of the root variable of the lock in the endpoint event
LockIdentity.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 event
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, (order, ui)) ->
(* skip methods known to run on ui thread, as they cannot run in parallel to us *)
if UIThreadDomain.is_empty ui then
LockOrderDomain.iter (report_remote_block elem endpoint_lock endpoint_pname) order
)
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.fold endpoint_summaries ~init:report_map ~f:
(fun acc (endpoint_pname, (order, ui)) ->
(* skip methods known to run on ui thread, as they cannot run in parallel to us *)
if UIThreadDomain.is_empty ui then
LockOrderDomain.fold
(report_remote_block ui_explain elem endpoint_lock endpoint_pname)
order acc
else acc ) )
in
LockOrderDomain.iter report_on_current_elem order
match ui with
| AbstractDomain.Types.Bottom ->
report_map'
| AbstractDomain.Types.NonBottom ui_explain ->
LockOrderDomain.fold (report_on_current_elem ui_explain) order report_map'
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 ((order, ui) as summary) ->
report_deadlocks tenv proc_desc summary ;
match ui with
| AbstractDomain.Types.Bottom ->
()
| AbstractDomain.Types.NonBottom on_ui ->
report_blocks_on_main_thread tenv proc_desc order on_ui )
|> Option.iter ~f:(fun summary ->
report_deadlocks tenv proc_desc summary ReportMap.empty
|> report_blocks_on_main_thread tenv proc_desc summary |> ReportMap.log )
in
List.iter procedures ~f:report_procedure ;
let sourcefile = exe_env.Exe_env.source_file in

@ -53,12 +53,15 @@ module LockIdentity = struct
end
module LockEvent = struct
type event_t = LockAcquire of LockIdentity.t | MayBlock of string [@@deriving compare]
type severity_t = Low | Medium | High [@@deriving compare]
type event_t = LockAcquire of LockIdentity.t | MayBlock of (string * severity_t)
[@@deriving compare]
let pp_event fmt = function
| LockAcquire lock ->
LockIdentity.pp fmt lock
| MayBlock msg ->
| MayBlock (msg, _) ->
F.pp_print_string fmt msg
@ -102,9 +105,9 @@ module LockEvent = struct
let make_acquire lock loc = {event= LockAcquire lock; loc; trace= []}
let make_blocks msg loc = {event= MayBlock msg; loc; trace= []}
let make_blocks msg sev loc = {event= MayBlock (msg, sev); loc; trace= []}
let make_blocking_call ~caller ~callee loc =
let make_blocking_call ~caller ~callee sev loc =
let descr =
F.asprintf "calls %a from %a"
(MF.wrap_monospaced Typ.Procname.pp)
@ -112,8 +115,10 @@ module LockEvent = struct
(MF.wrap_monospaced Typ.Procname.pp)
caller
in
make_blocks descr loc
make_blocks descr sev loc
let get_loc {loc; trace} = List.hd trace |> Option.value_map ~default:loc ~f:CallSite.loc
let make_loc_trace ?(reverse= false) e =
let call_trace, nesting =
@ -165,6 +170,10 @@ module LockOrder = struct
eventually= {o.eventually with LockEvent.trace= callsite :: o.eventually.LockEvent.trace} }
let get_loc {first; eventually} =
match first with Some event -> LockEvent.get_loc event | None -> LockEvent.get_loc eventually
let make_loc_trace o =
let first_trace =
Option.value_map o.first ~default:[] ~f:(LockEvent.make_loc_trace ~reverse:true)
@ -265,8 +274,8 @@ let acquire ((ls, lo), main) loc lockid =
((ls', lo'), main)
let blocking_call ~caller ~callee loc ((ls, lo), main) =
let newlock_event = LockEvent.make_blocking_call ~caller ~callee loc in
let blocking_call ~caller ~callee sev loc ((ls, lo), main) =
let newlock_event = LockEvent.make_blocking_call ~caller ~callee sev loc in
let lo' = add_order_pairs ls newlock_event lo in
((ls, lo'), main)

@ -23,7 +23,10 @@ end
(** A lock event. Equality/comparison disregards the call trace but includes location. *)
module LockEvent : sig
type event_t = private LockAcquire of LockIdentity.t | MayBlock of string
type severity_t = Low | Medium | High [@@deriving compare]
type event_t = LockAcquire of LockIdentity.t | MayBlock of (string * severity_t)
[@@deriving compare]
val pp_event : F.formatter -> event_t -> unit
@ -47,6 +50,8 @@ module LockOrder : sig
variable name at the root of each path. *)
val make_loc_trace : t -> Errlog.loc_trace
val get_loc : t -> Location.t
end
module LockOrderDomain : sig
@ -65,7 +70,8 @@ val acquire : astate -> Location.t -> LockIdentity.t -> astate
val release : astate -> LockIdentity.t -> astate
val blocking_call :
caller:Typ.Procname.t -> callee:Typ.Procname.t -> Location.t -> astate -> astate
caller:Typ.Procname.t -> callee:Typ.Procname.t -> LockEvent.severity_t -> Location.t -> 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

@ -0,0 +1,32 @@
/*
* Copyright (c) 2018 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
import java.io.FileReader;
import java.util.concurrent.CountDownLatch;
import android.support.annotation.UiThread;
import java.io.IOException;
class Dedup {
FileReader reader;
CountDownLatch latch;
// only one report should be seen
@UiThread
void onUiThreadBad() throws InterruptedException, IOException {
callMethodWithMultipleBlocksBad();
}
// three reports are expected
@UiThread
void callMethodWithMultipleBlocksBad() throws InterruptedException, IOException {
reader.read();
latch.await();
reader.read();
}
}

@ -1,29 +1,33 @@
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/AccMgr.java, void AccMgr.lockOnUiThreadBad(), 27, 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(), 22, STARVATION, ERROR, [ `void AccMgr.onUiThreadBad()`,calls `void AccountManager.setUserData(Account,String,String)` from `void AccMgr.onUiThreadBad()`]
codetoanalyze/java/starvation/AsyncTaskGet.java, void AsyncTaskGet.lockOnUiThreadBad(), 33, 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(), 22, STARVATION, ERROR, [ `void AsyncTaskGet.taskGetOnUiThreadBad()`,calls `Object AsyncTask.get()` from `void AsyncTaskGet.taskGetOnUiThreadBad()`]
codetoanalyze/java/starvation/Binders.java, void Binders.annotationBad(), 37, 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(), 26, 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(), 32, 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(), 23, STARVATION, ERROR, [ `void Countdwn.awaitOnMainByAnnotBad()`,calls `void CountDownLatch.await()` from `void Countdwn.awaitOnMainByAnnotBad()`]
codetoanalyze/java/starvation/Countdwn.java, void Countdwn.awaitOnMainByCallBad(), 18, STARVATION, ERROR, [ `void Countdwn.awaitOnMainByCallBad()`,calls `void CountDownLatch.await()` from `void Countdwn.awaitOnMainByCallBad()`]
codetoanalyze/java/starvation/Dedup.java, void Dedup.callMethodWithMultipleBlocksBad(), 28, STARVATION, ERROR, [ `void Dedup.callMethodWithMultipleBlocksBad()`,calls `int InputStreamReader.read()` from `void Dedup.callMethodWithMultipleBlocksBad()`]
codetoanalyze/java/starvation/Dedup.java, void Dedup.callMethodWithMultipleBlocksBad(), 29, STARVATION, ERROR, [ `void Dedup.callMethodWithMultipleBlocksBad()`,calls `void CountDownLatch.await()` from `void Dedup.callMethodWithMultipleBlocksBad()`]
codetoanalyze/java/starvation/Dedup.java, void Dedup.callMethodWithMultipleBlocksBad(), 30, STARVATION, ERROR, [ `void Dedup.callMethodWithMultipleBlocksBad()`,calls `int InputStreamReader.read()` from `void Dedup.callMethodWithMultipleBlocksBad()`]
codetoanalyze/java/starvation/Dedup.java, void Dedup.onUiThreadBad(), 22, STARVATION, 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(), 22, STARVATION, ERROR, [ `void FutureGet.getDirectBad()`,calls `Object Future.get()` from `void FutureGet.getDirectBad()`]
codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getIndirectBad(), 27, 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(), 78, STARVATION, ERROR, [ `void FutureGet.getTimeout50000001MicroSecondsBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeout50000001MicroSecondsBad()`]
codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getTimeoutOneDayBad(), 43, STARVATION, ERROR, [ `void FutureGet.getTimeoutOneDayBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeoutOneDayBad()`]
codetoanalyze/java/starvation/FutureGet.java, void FutureGet.getTimeoutOneHourBad(), 57, STARVATION, ERROR, [ `void FutureGet.getTimeoutOneHourBad()`,calls `Object Future.get(long,TimeUnit)` from `void FutureGet.getTimeoutOneHourBad()`]
codetoanalyze/java/starvation/IndirectBlock.java, void IndirectBlock.takeExpensiveLockOnUiThreadBad(), 24, 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), 35, 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), 50, 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/Intraproc.java, void Intraproc.intraBad(IntraprocA), 12, 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(), 33, 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(), 38, 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(), 27, 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), 21, 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(), 27, 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(), 25, 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(), 20, STARVATION, ERROR, [ `void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad()`,calls `void View.getWindowVisibleDisplayFrame(Rect)` from `void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad()`]

Loading…
Cancel
Save