[starvation] Move to a cluster checker phase for reporting

Reviewed By: jeremydubreil

Differential Revision: D7757783

fbshipit-source-id: 341de51
master
Nikos Gorogiannis 7 years ago committed by Facebook Github Bot
parent 30d7239aff
commit e0a61c0a4a

@ -105,7 +105,9 @@ let all_checkers =
} }
; { name= "Starvation analysis" ; { name= "Starvation analysis"
; active= Config.starvation ; active= Config.starvation
; callbacks= [(Procedure Starvation.analyze_procedure, Language.Java)] } ] ; callbacks=
[ (Procedure Starvation.analyze_procedure, Language.Java)
; (Cluster Starvation.reporting, Language.Java) ] } ]
let get_active_checkers () = let get_active_checkers () =

@ -100,27 +100,46 @@ end
module Analyzer = LowerHil.MakeAbstractInterpreter (ProcCfg.Normal) (TransferFunctions) module Analyzer = LowerHil.MakeAbstractInterpreter (ProcCfg.Normal) (TransferFunctions)
(* To allow on-demand reporting for deadlocks, we look for order pairs of the form (A,B) let get_class_of_pname = function
where A belongs to the current class and B is potentially another class. To avoid | Typ.Procname.Java java_pname ->
quadratic/double reporting (ie when we actually analyse B), we allow the check Some (Typ.Procname.Java.get_class_type_name java_pname)
only if the current class is ordered greater or equal to the callee class. *) | _ ->
let should_skip_during_deadlock_reporting _ _ = false None
(* currently short-circuited until non-determinism in reporting is dealt with *)
(* Typ.Name.compare current_class eventually_class < 0 *) let analyze_procedure {Callbacks.proc_desc; tenv; summary} =
(* let false_if_none a ~f = Option.value_map a ~default:false ~f *) let pname = Procdesc.get_proc_name proc_desc in
(* if same class, report only if the locks order in one of the possible ways *) let formals = FormalMap.make proc_desc in
let should_report_if_same_class _ = true let proc_data = ProcData.make proc_desc tenv formals in
let initial =
(* currently short-circuited until non-determinism in reporting is dealt with *) if not (Procdesc.is_java_synchronized proc_desc) then StarvationDomain.empty
(* StarvationDomain.( else
LockOrder.get_pair caller_elem let loc = Procdesc.get_loc proc_desc in
|> false_if_none ~f:(fun (b, a) -> let lock =
let b_class_opt, a_class_opt = (LockEvent.owner_class b, LockEvent.owner_class a) in if is_java_static pname then
false_if_none b_class_opt ~f:(fun first_class -> (* this is crafted so as to match synchronized(CLASSNAME.class) constructs *)
false_if_none a_class_opt ~f:(fun eventually_class -> get_class_of_pname pname
not (Typ.Name.equal first_class eventually_class) || LockEvent.compare b a >= 0 |> Option.map ~f:(fun tn -> Typ.Name.name tn |> Ident.string_to_name |> lock_of_class)
) ) )) *) else FormalMap.get_formal_base 0 formals |> Option.map ~f:(fun base -> (base, []))
in
Option.value_map lock ~default:StarvationDomain.empty
~f:(StarvationDomain.acquire StarvationDomain.empty loc)
in
let initial =
if RacerDConfig.Models.runs_on_ui_thread proc_desc then
StarvationDomain.set_on_main_thread initial
else initial
in
Analyzer.compute_post proc_data ~initial
|> Option.value_map ~default:summary ~f:(fun lock_state ->
let lock_order = StarvationDomain.to_summary lock_state in
Summary.update_summary lock_order summary )
let get_summary caller_pdesc callee_pdesc =
Summary.read_summary caller_pdesc (Procdesc.get_proc_name callee_pdesc)
|> Option.map ~f:(fun summary -> (callee_pdesc, summary))
let make_trace_with_header ?(header= "") elem start_loc pname = let make_trace_with_header ?(header= "") elem start_loc pname =
let trace = StarvationDomain.LockOrder.make_loc_trace elem in let trace = StarvationDomain.LockOrder.make_loc_trace elem in
@ -138,72 +157,67 @@ let make_loc_trace pname trace_id start_loc elem =
make_trace_with_header ~header elem start_loc pname make_trace_with_header ~header elem start_loc pname
let get_summary caller_pdesc callee_pdesc = (* Note about how many times we report a deadlock: normally twice, at each trace starting point.
Summary.read_summary caller_pdesc (Procdesc.get_proc_name callee_pdesc) Due to the fact we look for deadlocks in the summaries of the class at the root of a path,
|> Option.map ~f:(fun summary -> (callee_pdesc, summary)) this will fail when (a) the lock is of class type (ie as used in static sync methods), because
then the root is an identifier of type java.lang.Class and (b) when the lock belongs to an
inner class but this is no longer obvious in the path, because of nested-class path normalisation.
let get_class_of_pname = function The net effect of the above issues is that we will only see these locks in conflicting pairs
| Typ.Procname.Java java_pname -> once, as opposed to twice with all other deadlock pairs. *)
Some (Typ.Procname.Java.get_class_type_name java_pname) let report_deadlocks get_proc_desc tenv current_pdesc (summary, _) =
| _ ->
None
let report_deadlocks get_proc_desc tenv pdesc (summary, _) =
let open StarvationDomain in let open StarvationDomain in
let process_callee_elem caller_pdesc caller_elem callee_pdesc elem = let current_loc = Procdesc.get_loc current_pdesc in
if LockOrder.may_deadlock caller_elem elem && should_report_if_same_class caller_elem then ( let current_pname = Procdesc.get_proc_name current_pdesc in
debug "Possible deadlock:@.%a@.%a@." LockOrder.pp caller_elem LockOrder.pp elem ; let report_endpoint_elem current_elem endpoint_pname endpoint_loc elem =
let caller_loc = Procdesc.get_loc caller_pdesc in if LockOrder.may_deadlock current_elem elem then
let callee_loc = Procdesc.get_loc callee_pdesc in let () = debug "Possible deadlock:@.%a@.%a@." LockOrder.pp current_elem LockOrder.pp elem in
let caller_pname = Procdesc.get_proc_name caller_pdesc in match (current_elem.LockOrder.eventually, elem.LockOrder.eventually) with
let callee_pname = Procdesc.get_proc_name callee_pdesc in | {LockEvent.event= LockAcquire _}, {LockEvent.event= LockAcquire _} ->
match
( caller_elem.LockOrder.eventually.LockEvent.event
, elem.LockOrder.eventually.LockEvent.event )
with
| LockEvent.LockAcquire lock, LockEvent.LockAcquire lock' ->
let error_message = let error_message =
Format.asprintf "Potential deadlock (%a ; %a)" LockIdentity.pp lock LockIdentity.pp Format.asprintf
lock' "Potential deadlock.@.Trace 1 (starts at %a), %a.@.Trace 2 (starts at %a), %a."
Typ.Procname.pp current_pname LockOrder.pp current_elem Typ.Procname.pp
endpoint_pname LockOrder.pp elem
in in
let exn = let exn =
Exceptions.Checkers (IssueType.starvation, Localise.verbatim_desc error_message) Exceptions.Checkers (IssueType.starvation, Localise.verbatim_desc error_message)
in in
let first_trace = List.rev (make_loc_trace caller_pname 1 caller_loc caller_elem) in let first_trace = List.rev (make_loc_trace current_pname 1 current_loc current_elem) in
let second_trace = make_loc_trace callee_pname 2 callee_loc elem in let second_trace = make_loc_trace endpoint_pname 2 endpoint_loc elem in
let ltr = List.rev_append first_trace second_trace in let ltr = List.rev_append first_trace second_trace in
Specs.get_summary caller_pname Reporting.log_error_deprecated ~store_summary:true current_pname ~loc:current_loc ~ltr
|> Option.iter ~f:(fun summary -> Reporting.log_error summary ~loc:caller_loc ~ltr exn) exn
| _, _ -> | _, _ ->
() ) ()
in in
let report_pair current_class elem = let report_on_current_elem elem =
LockOrder.get_pair elem match elem with
|> Option.iter ~f:(fun (_, eventually) -> | {LockOrder.first= None} | {LockOrder.eventually= {LockEvent.event= LockEvent.MayBlock _}} ->
LockEvent.owner_class eventually ()
|> Option.iter ~f:(fun eventually_class -> | {LockOrder.eventually= {LockEvent.event= LockEvent.LockAcquire endpoint_lock}} ->
if should_skip_during_deadlock_reporting current_class eventually_class then () match LockIdentity.owner_class endpoint_lock with
else | None ->
(* 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 *) | Some endpoint_class ->
let class_of_eventual_lock = (* get the class of the root variable of the lock in the endpoint event
LockEvent.owner_class eventually |> Option.bind ~f:(Tenv.lookup tenv) and retrieve all the summaries of the methods of that class *)
in let endpoint_tstruct = Tenv.lookup tenv endpoint_class in
let methods = let methods =
Option.value_map class_of_eventual_lock ~default:[] ~f:(fun tstruct -> Option.value_map endpoint_tstruct ~default:[] ~f:(fun tstruct ->
tstruct.Typ.Struct.methods ) tstruct.Typ.Struct.methods )
in in
let proc_descs = List.rev_filter_map methods ~f:get_proc_desc in let endpoint_pdescs = List.rev_filter_map methods ~f:get_proc_desc in
let summaries = List.rev_filter_map proc_descs ~f:(get_summary pdesc) in let endpoint_summaries =
(* for each summary related to the endpoint, analyse and report on its pairs *) List.rev_filter_map endpoint_pdescs ~f:(get_summary current_pdesc)
List.iter summaries ~f:(fun (callee_pdesc, (summary, _)) -> in
LockOrderDomain.iter (process_callee_elem pdesc elem callee_pdesc) summary (* for each summary related to the endpoint, analyse and report on its pairs *)
) ) ) List.iter endpoint_summaries ~f:(fun (endpoint_pdesc, (summary, _)) ->
let endpoint_loc = Procdesc.get_loc endpoint_pdesc in
let endpoint_pname = Procdesc.get_proc_name endpoint_pdesc in
LockOrderDomain.iter (report_endpoint_elem elem endpoint_pname endpoint_loc) summary
)
in in
Procdesc.get_proc_name pdesc |> get_class_of_pname LockOrderDomain.iter report_on_current_elem summary
|> Option.iter ~f:(fun curr_class -> LockOrderDomain.iter (report_pair curr_class) summary)
let report_direct_blocks_on_main_thread proc_desc summary = let report_direct_blocks_on_main_thread proc_desc summary =
@ -211,8 +225,8 @@ let report_direct_blocks_on_main_thread proc_desc summary =
let report_pair ({LockOrder.eventually} as elem) = let report_pair ({LockOrder.eventually} as elem) =
match eventually with match eventually with
| {LockEvent.event= LockEvent.MayBlock _} -> | {LockEvent.event= LockEvent.MayBlock _} ->
let caller_loc = Procdesc.get_loc proc_desc in let current_loc = Procdesc.get_loc proc_desc in
let caller_pname = Procdesc.get_proc_name proc_desc in let current_pname = Procdesc.get_proc_name proc_desc in
let error_message = let error_message =
Format.asprintf "UI-thread method may block; %a" LockEvent.pp_event Format.asprintf "UI-thread method may block; %a" LockEvent.pp_event
eventually.LockEvent.event eventually.LockEvent.event
@ -220,46 +234,19 @@ let report_direct_blocks_on_main_thread proc_desc summary =
let exn = let exn =
Exceptions.Checkers (IssueType.starvation, Localise.verbatim_desc error_message) Exceptions.Checkers (IssueType.starvation, Localise.verbatim_desc error_message)
in in
let ltr = make_trace_with_header elem caller_loc caller_pname in let ltr = make_trace_with_header elem current_loc current_pname in
Specs.get_summary caller_pname Reporting.log_error_deprecated ~store_summary:true current_pname ~loc:current_loc ~ltr exn
|> Option.iter ~f:(fun summary -> Reporting.log_error summary ~loc:caller_loc ~ltr exn)
| _ -> | _ ->
() ()
in in
LockOrderDomain.iter report_pair summary LockOrderDomain.iter report_pair summary
let analyze_procedure {Callbacks.proc_desc; get_proc_desc; tenv; summary} = let reporting {Callbacks.procedures; get_proc_desc} =
let pname = Procdesc.get_proc_name proc_desc in let report_procedure (tenv, proc_desc) =
let formals = FormalMap.make proc_desc in Summary.read_summary proc_desc (Procdesc.get_proc_name proc_desc)
let proc_data = ProcData.make proc_desc tenv formals in |> Option.iter ~f:(fun ((s, main) as summary) ->
let initial = report_deadlocks get_proc_desc tenv proc_desc summary ;
if not (Procdesc.is_java_synchronized proc_desc) then StarvationDomain.empty if main then report_direct_blocks_on_main_thread proc_desc s )
else
let loc = Procdesc.get_loc proc_desc in
let lock =
if is_java_static pname then
(* this is crafted so as to match synchronized(CLASSNAME.class) constructs *)
get_class_of_pname pname
|> Option.map ~f:(fun tn -> Typ.Name.name tn |> Ident.string_to_name |> lock_of_class)
else FormalMap.get_formal_base 0 formals |> Option.map ~f:(fun base -> (base, []))
in
Option.value_map lock ~default:StarvationDomain.empty
~f:(StarvationDomain.acquire StarvationDomain.empty loc)
in
let initial =
if RacerDConfig.Models.runs_on_ui_thread proc_desc then
StarvationDomain.set_on_main_thread initial
else initial
in in
match Analyzer.compute_post proc_data ~initial with List.iter procedures ~f:report_procedure
| None ->
summary
| Some lock_state ->
let lock_order = StarvationDomain.to_summary lock_state in
let updated_summary = Summary.update_summary lock_order summary in
Option.iter updated_summary.Specs.payload.starvation
~f:(report_deadlocks get_proc_desc tenv proc_desc) ;
Option.iter updated_summary.Specs.payload.starvation ~f:(fun (sum, main) ->
if main then report_direct_blocks_on_main_thread proc_desc sum ) ;
updated_summary

@ -10,3 +10,5 @@
open! IStd open! IStd
val analyze_procedure : Callbacks.proc_callback_t val analyze_procedure : Callbacks.proc_callback_t
val reporting : Callbacks.cluster_callback_t

@ -41,7 +41,10 @@ module LockIdentity = struct
let pp fmt (((_, typ), _) as lock) = 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`" AccessPath.pp lock (Typ.pp_full Pp.text) typ
let owner_class ((_, typ), _) = Typ.inner_name typ
end end
module LockEvent = struct module LockEvent = struct
@ -92,15 +95,6 @@ module LockEvent = struct
F.fprintf fmt "%a at %a%a" pp_event e.event Location.pp e.loc pp_trace e.trace F.fprintf fmt "%a at %a%a" pp_event e.event Location.pp e.loc pp_trace e.trace
let owner_class e =
match e.event with
| LockAcquire lock ->
let (_, typ), _ = lock in
Typ.inner_name typ
| _ ->
None
let make_acquire lock loc = {event= LockAcquire lock; loc; trace= []} let make_acquire lock loc = {event= LockAcquire lock; loc; trace= []}
let make_blocks msg loc = {event= MayBlock msg; loc; trace= []} let make_blocks msg loc = {event= MayBlock msg; loc; trace= []}
@ -137,8 +131,6 @@ module LockOrder = struct
o.eventually o.eventually
let get_pair elem = match elem.first with None -> None | Some b -> Some (b, elem.eventually)
let may_deadlock elem elem' = let may_deadlock elem elem' =
match (elem.first, elem'.first) with match (elem.first, elem'.first) with
| Some b, Some b' -> | Some b, Some b' ->

@ -12,7 +12,12 @@ module F = Format
(** Abstraction of a path that represents a lock, special-casing equality and comparisons (** Abstraction of a path that represents a lock, special-casing equality and comparisons
to work over type, base variable modulo this and access list *) to work over type, base variable modulo this and access list *)
module LockIdentity : PrettyPrintable.PrintableOrderedType with type t = AccessPath.t module LockIdentity : sig
include PrettyPrintable.PrintableOrderedType with type t = AccessPath.t
val owner_class : t -> Typ.name option
(** Class of the root variable of the path representing the lock *)
end
(** A lock event. Equality/comparison disregards the call trace but includes location. *) (** A lock event. Equality/comparison disregards the call trace but includes location. *)
module LockEvent : sig module LockEvent : sig
@ -23,9 +28,6 @@ module LockEvent : sig
type t = private {event: event_t; loc: Location.t; trace: CallSite.t list} type t = private {event: event_t; loc: Location.t; trace: CallSite.t list}
include PrettyPrintable.PrintableOrderedType with type t := t include PrettyPrintable.PrintableOrderedType with type t := t
val owner_class : t -> Typ.name option
(** Class of the root variable of the path representing the lock *)
end end
module LockState : AbstractDomain.WithBottom module LockState : AbstractDomain.WithBottom
@ -40,9 +42,6 @@ module LockOrder : sig
include PrettyPrintable.PrintableOrderedType with type t := t include PrettyPrintable.PrintableOrderedType with type t := t
val get_pair : t -> (LockEvent.t * LockEvent.t) option
(** return the pair (b, eventually) if first is Some b *)
val may_deadlock : t -> t -> bool val may_deadlock : t -> t -> bool
(** check if two pairs are symmetric in terms of locks, where locks are compared modulo the (** check if two pairs are symmetric in terms of locks, where locks are compared modulo the
variable name at the root of each path. *) variable name at the root of each path. *)

@ -3,12 +3,17 @@ codetoanalyze/java/starvation/Binders.java, void Binders.interBad(), 0, STARVATI
codetoanalyze/java/starvation/Binders.java, void Binders.intraBad(), 0, STARVATION, ERROR, [Method start: void Binders.intraBad(),Method call: void Binders.doTransact(),calls boolean Binder.transact(int,Parcel,Parcel,int) from void Binders.doTransact()] codetoanalyze/java/starvation/Binders.java, void Binders.intraBad(), 0, STARVATION, ERROR, [Method start: 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(), 0, STARVATION, ERROR, [Method start: void Countdwn.awaitOnMainByAnnotBad(),calls void CountDownLatch.await() from void Countdwn.awaitOnMainByAnnotBad()] codetoanalyze/java/starvation/Countdwn.java, void Countdwn.awaitOnMainByAnnotBad(), 0, STARVATION, ERROR, [Method start: void Countdwn.awaitOnMainByAnnotBad(),calls void CountDownLatch.await() from void Countdwn.awaitOnMainByAnnotBad()]
codetoanalyze/java/starvation/Countdwn.java, void Countdwn.awaitOnMainByCallBad(), 0, STARVATION, ERROR, [Method start: void Countdwn.awaitOnMainByCallBad(),calls void CountDownLatch.await() from void Countdwn.awaitOnMainByCallBad()] codetoanalyze/java/starvation/Countdwn.java, void Countdwn.awaitOnMainByCallBad(), 0, STARVATION, ERROR, [Method start: void Countdwn.awaitOnMainByCallBad(),calls void CountDownLatch.await() from void Countdwn.awaitOnMainByCallBad()]
codetoanalyze/java/starvation/InnerClass.java, void InnerClass$InnerClassA.innerOuterBad(), 0, STARVATION, ERROR, [[Trace 1] Locks this in class InnerClass$InnerClassA*,Method call: void InnerClass.bar(),Locks this in class InnerClass*,[Trace 2] Locks this in class InnerClass*,Method call: void InnerClass$InnerClassA.baz(),Locks this in class InnerClass$InnerClassA*] codetoanalyze/java/starvation/InnerClass.java, InnerClass$InnerClassA.<init>(InnerClass,Object), 0, STARVATION, ERROR, [[Trace 1] Method start: InnerClass$InnerClassA.<init>(InnerClass,Object),locks `this` in class `InnerClass$InnerClassA*`,Method call: void InnerClass.bar(),locks `this` in class `InnerClass*`,[Trace 2] locks `this` in class `InnerClass*`,Method call: void InnerClass$InnerClassA.baz(),locks `this` in class `InnerClass$InnerClassA*`]
codetoanalyze/java/starvation/InnerClass.java, void InnerClass.outerInnerBad(InnerClass$InnerClassA), 0, STARVATION, ERROR, [[Trace 1] Locks this in class InnerClass*,Method call: void InnerClass$InnerClassA.baz(),Locks this in class InnerClass$InnerClassA*,[Trace 2] Method start: InnerClass$InnerClassA.<init>(InnerClass,Object),Locks this in class InnerClass$InnerClassA*,Method call: void InnerClass.bar(),Locks this in class InnerClass*] codetoanalyze/java/starvation/InnerClass.java, void InnerClass$InnerClassA.innerOuterBad(), 0, STARVATION, ERROR, [[Trace 1] locks `this` in class `InnerClass$InnerClassA*`,Method call: void InnerClass.bar(),locks `this` in class `InnerClass*`,[Trace 2] locks `this` in class `InnerClass*`,Method call: void InnerClass$InnerClassA.baz(),locks `this` in class `InnerClass$InnerClassA*`]
codetoanalyze/java/starvation/Interclass.java, void InterclassA.interclass2Bad(Interclass), 0, STARVATION, ERROR, [[Trace 1] Locks this in class InterclassA*,Method call: void Interclass.interclass2Bad(),Locks this in class Interclass*,[Trace 2] Locks this in class Interclass*,Method call: void InterclassA.interclass1Bad(),Locks this in class InterclassA*] codetoanalyze/java/starvation/InnerClass.java, void InnerClass.outerInnerBad(InnerClass$InnerClassA), 0, STARVATION, ERROR, [[Trace 1] locks `this` in class `InnerClass*`,Method call: void InnerClass$InnerClassA.baz(),locks `this` in class `InnerClass$InnerClassA*`,[Trace 2] locks `this` in class `InnerClass$InnerClassA*`,Method call: void InnerClass.bar(),locks `this` in class `InnerClass*`]
codetoanalyze/java/starvation/Interproc.java, void Interproc.interproc1Bad(InterprocA), 0, STARVATION, ERROR, [[Trace 1] Locks this in class Interproc*,Method call: void Interproc.interproc2Bad(InterprocA),Locks b in class InterprocA*,[Trace 2] Locks this in class InterprocA*,Method call: void InterprocA.interproc2Bad(Interproc),Locks d in class Interproc*] codetoanalyze/java/starvation/InnerClass.java, void InnerClass.outerInnerBad(InnerClass$InnerClassA), 0, STARVATION, ERROR, [[Trace 1] locks `this` in class `InnerClass*`,Method call: void InnerClass$InnerClassA.baz(),locks `this` in class `InnerClass$InnerClassA*`,[Trace 2] Method start: InnerClass$InnerClassA.<init>(InnerClass,Object),locks `this` in class `InnerClass$InnerClassA*`,Method call: void InnerClass.bar(),locks `this` in class `InnerClass*`]
codetoanalyze/java/starvation/Intraproc.java, void IntraprocA.intraBad(Intraproc), 0, STARVATION, ERROR, [[Trace 1] Method start: void IntraprocA.intraBad(Intraproc),Locks this in class IntraprocA*,Locks o in class Intraproc*,[Trace 2] Method start: void Intraproc.intraBad(IntraprocA),Locks this in class Intraproc*,Locks o in class IntraprocA*] codetoanalyze/java/starvation/Interclass.java, void Interclass.interclass1Bad(InterclassA), 0, STARVATION, ERROR, [[Trace 1] locks `this` in class `Interclass*`,Method call: void InterclassA.interclass1Bad(),locks `this` in class `InterclassA*`,[Trace 2] locks `this` in class `InterclassA*`,Method call: void Interclass.interclass2Bad(),locks `this` in class `Interclass*`]
codetoanalyze/java/starvation/Interclass.java, void InterclassA.interclass2Bad(Interclass), 0, STARVATION, ERROR, [[Trace 1] locks `this` in class `InterclassA*`,Method call: void Interclass.interclass2Bad(),locks `this` in class `Interclass*`,[Trace 2] locks `this` in class `Interclass*`,Method call: void InterclassA.interclass1Bad(),locks `this` in class `InterclassA*`]
codetoanalyze/java/starvation/Interproc.java, void Interproc.interproc1Bad(InterprocA), 0, STARVATION, ERROR, [[Trace 1] locks `this` in class `Interproc*`,Method call: void Interproc.interproc2Bad(InterprocA),locks `b` in class `InterprocA*`,[Trace 2] locks `this` in class `InterprocA*`,Method call: void InterprocA.interproc2Bad(Interproc),locks `d` in class `Interproc*`]
codetoanalyze/java/starvation/Interproc.java, void InterprocA.interproc1Bad(Interproc), 0, STARVATION, ERROR, [[Trace 1] locks `this` in class `InterprocA*`,Method call: void InterprocA.interproc2Bad(Interproc),locks `d` in class `Interproc*`,[Trace 2] locks `this` in class `Interproc*`,Method call: void Interproc.interproc2Bad(InterprocA),locks `b` in class `InterprocA*`]
codetoanalyze/java/starvation/Intraproc.java, void Intraproc.intraBad(IntraprocA), 0, STARVATION, ERROR, [[Trace 1] Method start: void Intraproc.intraBad(IntraprocA),locks `this` in class `Intraproc*`,locks `o` in class `IntraprocA*`,[Trace 2] Method start: void IntraprocA.intraBad(Intraproc),locks `this` in class `IntraprocA*`,locks `o` in class `Intraproc*`]
codetoanalyze/java/starvation/Intraproc.java, void IntraprocA.intraBad(Intraproc), 0, STARVATION, ERROR, [[Trace 1] Method start: void IntraprocA.intraBad(Intraproc),locks `this` in class `IntraprocA*`,locks `o` in class `Intraproc*`,[Trace 2] Method start: void Intraproc.intraBad(IntraprocA),locks `this` in class `Intraproc*`,locks `o` in class `IntraprocA*`]
codetoanalyze/java/starvation/JavaIO.java, void JavaIO.fileReadBad(), 0, STARVATION, ERROR, [Method start: void JavaIO.fileReadBad(),Method call: int JavaIO.doFileRead(),calls int InputStreamReader.read() from int JavaIO.doFileRead()] codetoanalyze/java/starvation/JavaIO.java, void JavaIO.fileReadBad(), 0, STARVATION, ERROR, [Method start: void JavaIO.fileReadBad(),Method call: int JavaIO.doFileRead(),calls int InputStreamReader.read() from int JavaIO.doFileRead()]
codetoanalyze/java/starvation/JavaIO.java, void JavaIO.streamReadBad(), 0, STARVATION, ERROR, [Method start: void JavaIO.streamReadBad(),Method call: String JavaIO.doStreamRead(),calls String DataInputStream.readUTF() from String JavaIO.doStreamRead()] codetoanalyze/java/starvation/JavaIO.java, void JavaIO.streamReadBad(), 0, STARVATION, ERROR, [Method start: void JavaIO.streamReadBad(),Method call: String JavaIO.doStreamRead(),calls String DataInputStream.readUTF() from String JavaIO.doStreamRead()]
codetoanalyze/java/starvation/StaticLock.java, void StaticLock.lockOtherClassOneWayBad(), 0, STARVATION, ERROR, [[Trace 1] Method start: void StaticLock.lockOtherClassOneWayBad(),Locks StaticLock$0 in class java.lang.Class*,Locks this in class StaticLock*,[Trace 2] Locks this in class StaticLock*,Method call: void StaticLock.staticSynced(),Locks StaticLock$0 in class java.lang.Class*] codetoanalyze/java/starvation/StaticLock.java, void StaticLock.lockOtherClassOneWayBad(), 0, STARVATION, ERROR, [[Trace 1] Method start: void StaticLock.lockOtherClassOneWayBad(),locks `StaticLock$0` in class `java.lang.Class*`,locks `this` in class `StaticLock*`,[Trace 2] locks `this` in class `StaticLock*`,Method call: void StaticLock.staticSynced(),locks `StaticLock$0` in class `java.lang.Class*`]
codetoanalyze/java/starvation/VisDispFrame.java, void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad(), 0, STARVATION, ERROR, [Method start: void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad(),calls void View.getWindowVisibleDisplayFrame(Rect) from void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad()] codetoanalyze/java/starvation/VisDispFrame.java, void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad(), 0, STARVATION, ERROR, [Method start: void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad(),calls void View.getWindowVisibleDisplayFrame(Rect) from void VisDispFrame.callsGetVisibleDisplayFrameOnUiThreadBad()]

Loading…
Cancel
Save