[racerd] reconcile java and clang report corellation code

Summary:
Use same code for deciding whether two accesses conflict across java/clang, by adapting that of the clang version.
Eliminate/simplify some code.

Reviewed By: mbouaziz, jberdine

Differential Revision: D10217383

fbshipit-source-id: dc0986d05
master
Nikos Gorogiannis 6 years ago committed by Facebook Github Bot
parent 08a26d4ba1
commit 9eecd1bb9b

@ -164,15 +164,3 @@ let store_global tenv =
frontend and backend run in the same process *) frontend and backend run in the same process *)
global_tenv := Some tenv ; global_tenv := Some tenv ;
store_to_filename tenv global_tenv_path store_to_filename tenv global_tenv_path
exception Found of Typ.Name.t
let language_is tenv lang =
match TypenameHash.iter (fun n -> raise (Found n)) tenv with
| () ->
false
| exception Found (JavaClass _) ->
Language.equal lang Java
| exception Found _ ->
Language.equal lang Clang

@ -47,9 +47,6 @@ val add_field : t -> Typ.Name.t -> Typ.Struct.field -> unit
val pp : Format.formatter -> t -> unit [@@warning "-32"] val pp : Format.formatter -> t -> unit [@@warning "-32"]
(** print a type environment *) (** print a type environment *)
val language_is : t -> Language.t -> bool
(** Test the language from which the types in the tenv were translated *)
type per_file = Global | FileLocal of t type per_file = Global | FileLocal of t
val pp_per_file : Format.formatter -> per_file -> unit val pp_per_file : Format.formatter -> per_file -> unit

@ -15,11 +15,13 @@ type t = LogicalVar of Ident.t | ProgramVar of Pvar.t [@@deriving compare]
let equal = [%compare.equal: t] let equal = [%compare.equal: t]
let compare_modulo_this x y = let compare_modulo_this x y =
match (x, y) with if phys_equal x y then 0
| ProgramVar i, ProgramVar j -> else
Pvar.compare_modulo_this i j match (x, y) with
| _, _ -> | ProgramVar i, ProgramVar j ->
compare x y Pvar.compare_modulo_this i j
| _, _ ->
compare x y
let of_id id = LogicalVar id let of_id id = LogicalVar id

@ -726,8 +726,6 @@ let analyze_procedure {Callbacks.proc_desc; tenv; summary} =
else Payload.update_summary empty_post summary else Payload.update_summary empty_post summary
module AccessListMap = Caml.Map.Make (RacerDDomain.Access)
type conflict = RacerDDomain.TraceElem.t type conflict = RacerDDomain.TraceElem.t
type report_kind = type report_kind =
@ -1016,6 +1014,81 @@ let empty_reported =
{reported_sites; reported_reads; reported_writes; reported_unannotated_calls} {reported_sites; reported_reads; reported_writes; reported_unannotated_calls}
(* decide if we should throw away a path before doing safety analysis
for now, just check for whether the access is within a switch-map
that is auto-generated by Java. *)
let should_filter_access path_opt =
let check_access = function
| AccessPath.ArrayAccess _ ->
false
| AccessPath.FieldAccess fld ->
String.is_substring ~substring:"$SwitchMap" (Typ.Fieldname.to_string fld)
in
Option.value_map path_opt ~default:false ~f:(fun (_, path) -> List.exists path ~f:check_access)
(**
Map containing reported accesses, which groups them in lists, by abstract location.
The equivalence relation used for grouping them is equality of access paths.
This is slightly complicated because local variables contain the pname of the function declaring
them. Here we want a purely name-based comparison, and in particular that [this == this]
regardless the method declaring it. Hence the redefined comparison functions.
*)
module ReportMap : sig
type t
val empty : t
val add : reported_access -> t -> t
val fold : (reported_access list -> 'a -> 'a) -> t -> 'a -> 'a
end = struct
module PathModuloThis : Caml.Map.OrderedType with type t = AccessPath.t = struct
type t = AccessPath.t
type var_ = Var.t
let compare_var_ = Var.compare_modulo_this
let compare = [%compare: (var_ * Typ.t) * AccessPath.access list]
end
module Key = struct
type t =
| Location of PathModuloThis.t
| Container of PathModuloThis.t
| Call of Typ.Procname.t
[@@deriving compare]
let of_access (access : RacerDDomain.Access.t) =
match access with
| Read ap | Write ap ->
Location ap
| ContainerRead (ap, _) | ContainerWrite (ap, _) ->
Container ap
| InterfaceCall pn ->
Call pn
end
module M = Caml.Map.Make (Key)
type t = reported_access list M.t
let empty = M.empty
let add (rep : reported_access) map =
let access = RacerDDomain.TraceElem.kind rep.snapshot.access in
if RacerDDomain.Access.get_access_path access |> should_filter_access then map
else
let k = Key.of_access access in
M.update k (function None -> Some [rep] | Some reps -> Some (rep :: reps)) map
let fold f map a =
let f _ v acc = f v acc in
M.fold f map a
end
(** Report accesses that may race with each other. (** Report accesses that may race with each other.
Principles for race reporting. Principles for race reporting.
@ -1044,7 +1117,7 @@ let empty_reported =
currently not distinguishing different locks, and are treating "known to be confined to a currently not distinguishing different locks, and are treating "known to be confined to a
thread" as if "known to be confined to UI thread". thread" as if "known to be confined to UI thread".
*) *)
let report_unsafe_accesses (aggregated_access_map : reported_access list AccessListMap.t) = let report_unsafe_accesses (aggregated_access_map : ReportMap.t) =
let open RacerDDomain in let open RacerDDomain in
let open RacerDModels in let open RacerDModels in
let is_duplicate_report access pname let is_duplicate_report access pname
@ -1078,7 +1151,7 @@ let report_unsafe_accesses (aggregated_access_map : reported_access list AccessL
{reported with reported_unannotated_calls; reported_sites} {reported with reported_unannotated_calls; reported_sites}
else reported else reported
in in
let report_unsafe_access {snapshot; threads; tenv; procdesc; wobbly_paths} accesses reported_acc let report_unsafe_access accesses reported_acc {snapshot; threads; tenv; procdesc; wobbly_paths}
= =
let pname = Procdesc.get_proc_name procdesc in let pname = Procdesc.get_proc_name procdesc in
if is_duplicate_report snapshot.access pname reported_acc then reported_acc if is_duplicate_report snapshot.access pname reported_acc then reported_acc
@ -1129,32 +1202,25 @@ let report_unsafe_accesses (aggregated_access_map : reported_access list AccessL
(* Do not report unprotected writes when an access can't run in parallel with itself, or (* Do not report unprotected writes when an access can't run in parallel with itself, or
for ObjC_Cpp *) for ObjC_Cpp *)
reported_acc ) reported_acc )
| (Access.Read _ | ContainerRead _) when AccessSnapshot.is_unprotected snapshot -> | (Access.Read _ | ContainerRead _) when AccessSnapshot.is_unprotected snapshot -> (
(* unprotected read. report all writes as conflicts for java. for c++ filter out (* unprotected read. report all writes as conflicts for java. for c++ filter out
unprotected writes *) unprotected writes *)
let is_cpp_protected_write snapshot = let is_conflict {snapshot; threads= other_threads} =
Typ.Procname.is_java pname || not (AccessSnapshot.is_unprotected snapshot)
in
let is_conflict (snapshot : AccessSnapshot.t) other_thread =
TraceElem.is_write snapshot.access TraceElem.is_write snapshot.access
&& &&
if Typ.Procname.is_java pname then if Typ.Procname.is_java pname then
ThreadsDomain.is_any threads || ThreadsDomain.is_any other_thread ThreadsDomain.is_any threads || ThreadsDomain.is_any other_threads
else is_cpp_protected_write snapshot else not (AccessSnapshot.is_unprotected snapshot)
in
let all_writes =
List.filter
~f:(fun {snapshot; threads= other_threads} -> is_conflict snapshot other_threads)
accesses
in in
if not (List.is_empty all_writes) then ( match List.find ~f:is_conflict accesses with
let conflict = List.hd_exn all_writes in | None ->
report_thread_safety_violation tenv procdesc reported_acc
~make_description:(make_read_write_race_description ~read_is_sync:false conflict) | Some conflict ->
~report_kind:(ReadWriteRace conflict.snapshot.access) snapshot.access threads report_thread_safety_violation tenv procdesc
wobbly_paths ; ~make_description:(make_read_write_race_description ~read_is_sync:false conflict)
update_reported snapshot.access pname reported_acc ) ~report_kind:(ReadWriteRace conflict.snapshot.access) snapshot.access threads
else reported_acc wobbly_paths ;
update_reported snapshot.access pname reported_acc )
| Access.Read _ | ContainerRead _ -> | Access.Read _ | ContainerRead _ ->
(* protected read. report unprotected writes and opposite protected writes as conflicts *) (* protected read. report unprotected writes and opposite protected writes as conflicts *)
let can_conflict (snapshot1 : AccessSnapshot.t) (snapshot2 : AccessSnapshot.t) = let can_conflict (snapshot1 : AccessSnapshot.t) (snapshot2 : AccessSnapshot.t) =
@ -1181,220 +1247,62 @@ let report_unsafe_accesses (aggregated_access_map : reported_access list AccessL
update_reported snapshot.access pname reported_acc ) update_reported snapshot.access pname reported_acc )
else reported_acc else reported_acc
in in
AccessListMap.fold let report_accesses_on_location (grouped_accesses : reported_access list) reported_acc =
(fun _ (grouped_accesses : reported_access list) reported_acc -> (* reset the reported reads and writes for each memory location *)
(* reset the reported reads and writes for each memory location *) let reported =
let reported = { reported_acc with
{ reported_acc with reported_writes= Typ.Procname.Set.empty; reported_reads= Typ.Procname.Set.empty }
reported_writes= Typ.Procname.Set.empty; reported_reads= Typ.Procname.Set.empty }
in
let class_has_mutex_member objc_cpp tenv =
let class_name = Typ.Procname.ObjC_Cpp.get_class_type_name objc_cpp in
let matcher = QualifiedCppName.Match.of_fuzzy_qual_names ["std::mutex"] in
Option.exists (Tenv.lookup tenv class_name) ~f:(fun class_str ->
(* check if the class contains a member of type std::mutex *)
List.exists class_str.Typ.Struct.fields ~f:(fun (_, ft, _) ->
Option.exists (Typ.name ft) ~f:(fun name ->
QualifiedCppName.Match.match_qualifiers matcher (Typ.Name.qual_name name) ) )
)
in
let should_report pdesc tenv =
match Procdesc.get_proc_name pdesc with
| Java _ ->
(* report if
- the method/class of the access is thread-safe
(or an override or superclass is), or
- any access is in a field marked thread-safe (or an override) *)
List.exists
~f:(fun ({threads} : reported_access) -> ThreadsDomain.is_any threads)
grouped_accesses
&& should_report_on_proc pdesc tenv
| ObjC_Cpp objc_cpp ->
(* do not report if a procedure is private *)
Procdesc.get_access pdesc <> PredSymb.Private
&& (* report if the class has a mutex member *)
class_has_mutex_member objc_cpp tenv
| _ ->
false
in
let reportable_accesses =
List.filter ~f:(fun {tenv; procdesc} -> should_report procdesc tenv) grouped_accesses
in
List.fold
~f:(fun acc access -> report_unsafe_access access reportable_accesses acc)
reportable_accesses ~init:reported )
aggregated_access_map empty_reported
|> ignore
module type QuotientedAccessListMap = sig
type t
val empty : t
val add : RacerDDomain.Access.t -> reported_access -> t -> t
val quotient : t -> reported_access list AccessListMap.t
end
module SyntacticQuotientedAccessListMap : QuotientedAccessListMap = struct
module M = Caml.Map.Make (struct
type t = RacerDDomain.Access.t
type var_ = Var.t
let compare_var_ (u : Var.t) (v : Var.t) =
if phys_equal u v then 0
else
match (u, v) with
| LogicalVar i, LogicalVar j ->
Ident.compare i j
| ProgramVar x, ProgramVar y ->
Pvar.compare_modulo_this x y
| _ ->
Pervasives.compare u v
let compare (x : t) (y : t) =
match (x, y) with
| (Read ap1 | Write ap1), (Read ap2 | Write ap2)
| ( (ContainerRead (ap1, _) | ContainerWrite (ap1, _))
, (ContainerRead (ap2, _) | ContainerWrite (ap2, _)) ) ->
[%compare: (var_ * Typ.t) * AccessPath.access list] ap1 ap2
| (InterfaceCall _ | Read _ | Write _ | ContainerRead _ | ContainerWrite _), _ ->
RacerDDomain.Access.compare x y
end)
type t = reported_access list M.t
let empty = M.empty
let add k d m =
let ds = try M.find k m with Caml.Not_found -> [] in
M.add k (d :: ds) m
let quotient m = M.fold AccessListMap.add m AccessListMap.empty
end
module MayAliasQuotientedAccessListMap : QuotientedAccessListMap = struct
type t = reported_access list AccessListMap.t
let empty = AccessListMap.empty
let add = AccessListMap.add
let add k d m =
let ds = try AccessListMap.find k m with Caml.Not_found -> [] in
add k (d :: ds) m
let syntactic_equal_access_path tenv p1 p2 =
(* unsound, but effective: report that the containers alias if their access paths are
syntactically identical *)
match (fst p1, fst p2) with
| (Var.ProgramVar pvar1, typ1), (Var.ProgramVar pvar2, typ2)
when Pvar.is_this pvar1 && Pvar.is_this pvar2
&& ( Typ.equal typ1 typ2
|| Prover.Subtyping_check.check_subtype tenv typ1 typ2
|| Prover.Subtyping_check.check_subtype tenv typ2 typ1 ) ->
(* the `this` used in C.foo and C.bar will compare unequal if we're not careful `this` is
represented as a local pvar, and a local pvar contains its parent procedure name. Count
the `this`'s as equal if their types are compatible *)
AccessPath.equal_access_list (snd p1) (snd p2)
| _ ->
AccessPath.equal p1 p2
(* equivalence relation computing whether two access paths may refer
to the same heap location. *)
let may_alias tenv p1 p2 =
let open AccessPath in
phys_equal p1 p2
||
match (List.last_exn (snd p1), List.last_exn (snd p2)) with
| FieldAccess _, ArrayAccess _ | ArrayAccess _, FieldAccess _ ->
false
| _, _ ->
syntactic_equal_access_path tenv p1 p2
(* take a results table and quotient it by the may_alias relation *)
let quotient acc_map =
let rec aux acc m =
if AccessListMap.is_empty m then acc
else
let k, vals = AccessListMap.min_binding m in
let tenv =
(List.find_exn vals ~f:(fun {snapshot} ->
RacerDDomain.Access.equal (RacerDDomain.TraceElem.kind snapshot.access) k ))
.tenv
in
(* assumption: the tenv for k is sufficient for k' too *)
let k_part, non_k_part =
AccessListMap.partition
(fun k' _ ->
match (k, k') with
| (Read ap1 | Write ap1), (Read ap2 | Write ap2) ->
may_alias tenv ap1 ap2
| ( (ContainerRead (ap1, _) | ContainerWrite (ap1, _))
, (ContainerRead (ap2, _) | ContainerWrite (ap2, _)) ) ->
syntactic_equal_access_path tenv ap1 ap2
| _ ->
RacerDDomain.Access.equal k k' )
m
in
if AccessListMap.is_empty k_part then L.(die InternalError) "may_alias is not reflexive!" ;
let k_accesses = AccessListMap.fold (fun _ v acc' -> List.append v acc') k_part [] in
let new_acc = AccessListMap.add k k_accesses acc in
aux new_acc non_k_part
in in
aux AccessListMap.empty acc_map let class_has_mutex_member objc_cpp tenv =
end let class_name = Typ.Procname.ObjC_Cpp.get_class_type_name objc_cpp in
let matcher = QualifiedCppName.Match.of_fuzzy_qual_names ["std::mutex"] in
(* decide if we should throw away a path before doing safety analysis Option.exists (Tenv.lookup tenv class_name) ~f:(fun class_str ->
for now, just check for whether the access is within a switch-map (* check if the class contains a member of type std::mutex *)
that is auto-generated by Java. *) List.exists class_str.Typ.Struct.fields ~f:(fun (_, ft, _) ->
let should_filter_access access = Option.exists (Typ.name ft) ~f:(fun name ->
match RacerDDomain.Access.get_access_path access with QualifiedCppName.Match.match_qualifiers matcher (Typ.Name.qual_name name) ) ) )
| Some (_, path) -> in
let check_access_step = function let should_report {tenv; procdesc} =
| AccessPath.ArrayAccess _ -> match Procdesc.get_proc_name procdesc with
false | Java _ ->
| AccessPath.FieldAccess fld -> List.exists
String.is_substring ~substring:"$SwitchMap" (Typ.Fieldname.to_string fld) ~f:(fun ({threads} : reported_access) -> ThreadsDomain.is_any threads)
in grouped_accesses
List.exists path ~f:check_access_step && should_report_on_proc procdesc tenv
| None -> | ObjC_Cpp objc_cpp ->
false (* do not report if a procedure is private *)
Procdesc.get_access procdesc <> PredSymb.Private
&& (* report if the class has a mutex member *)
class_has_mutex_member objc_cpp tenv
| _ ->
false
in
let reportable_accesses = List.filter ~f:should_report grouped_accesses in
List.fold ~f:(report_unsafe_access reportable_accesses) reportable_accesses ~init:reported
in
ReportMap.fold report_accesses_on_location aggregated_access_map empty_reported |> ignore
(* create a map from [abstraction of a memory loc] -> accesses that (* create a map from [abstraction of a memory loc] -> accesses that
may touch that memory loc. for now, our abstraction is an access may touch that memory loc. for now, our abstraction is an access
path like x.f.g whose concretization is the set of memory cells path like x.f.g whose concretization is the set of memory cells
that x.f.g may point to during execution *) that x.f.g may point to during execution *)
let make_results_table (module AccessListMap : QuotientedAccessListMap) file_env = let make_results_table file_env =
let open RacerDDomain in let open RacerDDomain in
let aggregate_post {threads; accesses; wobbly_paths} tenv procdesc acc = let aggregate_post tenv procdesc acc {threads; accesses; wobbly_paths} =
AccessDomain.fold AccessDomain.fold
(fun snapshot acc -> (fun snapshot acc ->
let access_kind = TraceElem.kind snapshot.access in let reported_access : reported_access =
if should_filter_access access_kind then acc {threads; snapshot; tenv; procdesc; wobbly_paths}
else in
let reported_access : reported_access = ReportMap.add reported_access acc )
{threads; snapshot; tenv; procdesc; wobbly_paths}
in
AccessListMap.add access_kind reported_access acc )
accesses acc accesses acc
in in
let aggregate_posts acc (tenv, proc_desc) = let aggregate_posts acc (tenv, proc_desc) =
match Payload.read proc_desc (Procdesc.get_proc_name proc_desc) with Payload.read proc_desc (Procdesc.get_proc_name proc_desc)
| Some summary -> |> Option.fold ~init:acc ~f:(aggregate_post tenv proc_desc)
aggregate_post summary tenv proc_desc acc
| None ->
acc
in in
List.fold ~f:aggregate_posts file_env ~init:AccessListMap.empty |> AccessListMap.quotient List.fold ~f:aggregate_posts file_env ~init:ReportMap.empty
(* aggregate all of the procedures in the file env by their declaring (* aggregate all of the procedures in the file env by their declaring
@ -1410,10 +1318,8 @@ let aggregate_by_class file_env =
| _ -> | _ ->
"unknown" "unknown"
in in
let bucket = String.Map.update acc classname ~f:(function None -> [proc] | Some bucket -> proc :: bucket)
try String.Map.find_exn acc classname with Not_found_s _ | Caml.Not_found -> [] )
in
String.Map.set ~key:classname ~data:(proc :: bucket) acc )
~init:String.Map.empty ~init:String.Map.empty
@ -1422,12 +1328,6 @@ let aggregate_by_class file_env =
safety *) safety *)
let file_analysis {Callbacks.procedures; source_file} = let file_analysis {Callbacks.procedures; source_file} =
String.Map.iter String.Map.iter
~f:(fun class_env -> ~f:(fun class_env -> report_unsafe_accesses (make_results_table class_env))
let tenv = fst (List.hd_exn class_env) in
report_unsafe_accesses
(make_results_table
( if Tenv.language_is tenv Clang then (module SyntacticQuotientedAccessListMap)
else (module MayAliasQuotientedAccessListMap) )
class_env) )
(aggregate_by_class procedures) ; (aggregate_by_class procedures) ;
IssueLog.store Config.racerd_issues_dir_name source_file IssueLog.store Config.racerd_issues_dir_name source_file

@ -28,8 +28,6 @@ module Access = struct
| InterfaceCall of Typ.Procname.t | InterfaceCall of Typ.Procname.t
[@@deriving compare] [@@deriving compare]
let equal = [%compare.equal: t]
let suffix_matches (_, accesses1) (_, accesses2) = let suffix_matches (_, accesses1) (_, accesses2) =
match (List.rev accesses1, List.rev accesses2) with match (List.rev accesses1, List.rev accesses2) with
| access1 :: _, access2 :: _ -> | access1 :: _, access2 :: _ ->

@ -24,8 +24,6 @@ module Access : sig
between the formals and actuals *) between the formals and actuals *)
val get_access_path : t -> AccessPath.t option val get_access_path : t -> AccessPath.t option
val equal : t -> t -> bool
end end
module TraceElem : sig module TraceElem : sig

@ -88,8 +88,14 @@ class Containers {
mListNobodyWrites.size(); mListNobodyWrites.size();
} }
List mListSyncWrites;
synchronized void listSyncAddBad(String s) {
mListSyncWrites.add(s);
}
boolean listReadBad(String s) { boolean listReadBad(String s) {
return mList.contains(s); return mListSyncWrites.contains(s);
} }
void accessSafeListOk(CopyOnWriteArrayList list, int index) { void accessSafeListOk(CopyOnWriteArrayList list, int index) {

@ -26,26 +26,26 @@ codetoanalyze/java/racerd/Constructors.java, Constructors.singleton1Bad():Constr
codetoanalyze/java/racerd/Constructors.java, Constructors.singleton2Bad():Constructors, 63, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [<Read trace>,access to `Constructors.Constructors.sSingleton2`,<Write trace>,access to `Constructors.Constructors.sSingleton2`] codetoanalyze/java/racerd/Constructors.java, Constructors.singleton2Bad():Constructors, 63, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [<Read trace>,access to `Constructors.Constructors.sSingleton2`,<Write trace>,access to `Constructors.Constructors.sSingleton2`]
codetoanalyze/java/racerd/Constructors.java, Constructors.singleton2Bad():Constructors, 64, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [access to `Constructors.Constructors.sSingleton2`] codetoanalyze/java/racerd/Constructors.java, Constructors.singleton2Bad():Constructors, 64, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [access to `Constructors.Constructors.sSingleton2`]
codetoanalyze/java/racerd/Constructors.java, Constructors.singleton2Bad():Constructors, 66, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [<Read trace>,access to `Constructors.Constructors.sSingleton2`,<Write trace>,access to `Constructors.Constructors.sSingleton2`] codetoanalyze/java/racerd/Constructors.java, Constructors.singleton2Bad():Constructors, 66, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [<Read trace>,access to `Constructors.Constructors.sSingleton2`,<Write trace>,access to `Constructors.Constructors.sSingleton2`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.addToSimpleArrayMapBad(android.support.v4.util.SimpleArrayMap):void, 273, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `map` via call to `put`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.addToSimpleArrayMapBad(android.support.v4.util.SimpleArrayMap):void, 279, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `map` via call to `put`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.addToSparseArrayBad(android.util.SparseArray):void, 263, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `sparseArray` via call to `put`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.addToSparseArrayBad(android.util.SparseArray):void, 269, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `sparseArray` via call to `put`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.addToSparseArrayCompatBad(android.support.v4.util.SparseArrayCompat):void, 254, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `sparseArray` via call to `put`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.addToSparseArrayCompatBad(android.support.v4.util.SparseArrayCompat):void, 260, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `sparseArray` via call to `put`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.containerWrapperUnownedWriteBad(java.lang.Object):void, 161, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [call to Object ContainerWrapper.write(Object),call to Object ContainerWrapper._write(Object),Write to container `this.codetoanalyze.java.checkers.ContainerWrapper.children` via call to `add`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.containerWrapperUnownedWriteBad(java.lang.Object):void, 167, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [call to Object ContainerWrapper.write(Object),call to Object ContainerWrapper._write(Object),Write to container `this.codetoanalyze.java.checkers.ContainerWrapper.children` via call to `add`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.listAddAllBad(java.util.Collection):void, 55, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mList` via call to `addAll`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.listAddAllBad(java.util.Collection):void, 55, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mList` via call to `addAll`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.listAddBad1(java.lang.String):void, 47, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mList` via call to `add`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.listAddBad1(java.lang.String):void, 47, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mList` via call to `add`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.listAddBad2(int,java.lang.String):void, 51, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mList` via call to `add`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.listAddBad2(int,java.lang.String):void, 51, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mList` via call to `add`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.listClearBad():void, 59, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mList` via call to `clear`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.listClearBad():void, 59, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mList` via call to `clear`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.listReadBad(java.lang.String):boolean, 92, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [<Read trace>,Read of container `this.codetoanalyze.java.checkers.Containers.mList` via call to `contains`,<Write trace>,Write to container `this.codetoanalyze.java.checkers.Containers.mList` via call to `set`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.listReadBad(java.lang.String):boolean, 98, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [<Read trace>,Read of container `this.codetoanalyze.java.checkers.Containers.mListSyncWrites` via call to `contains`,<Write trace>,Write to container `this.codetoanalyze.java.checkers.Containers.mListSyncWrites` via call to `add`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.listRemoveBad1(int):void, 63, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mList` via call to `remove`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.listRemoveBad1(int):void, 63, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mList` via call to `remove`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.listRemoveBad2(java.lang.String):void, 67, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mList` via call to `remove`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.listRemoveBad2(java.lang.String):void, 67, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mList` via call to `remove`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.listSetBad(int,java.lang.String):void, 75, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mList` via call to `set`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.listSetBad(int,java.lang.String):void, 75, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mList` via call to `set`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.listSubclassWriteBad(java.util.ArrayList,int):void, 79, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `list` via call to `remove`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.listSubclassWriteBad(java.util.ArrayList,int):void, 79, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `list` via call to `remove`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.mapClearBad():void, 109, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mMap` via call to `clear`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.mapClearBad():void, 115, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mMap` via call to `clear`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.mapPutAllBad(java.util.Map):void, 113, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mMap` via call to `putAll`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.mapPutAllBad(java.util.Map):void, 119, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mMap` via call to `putAll`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.mapPutBad(java.lang.String,java.lang.String):void, 101, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mMap` via call to `put`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.mapPutBad(java.lang.String,java.lang.String):void, 107, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mMap` via call to `put`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.mapRemoveBad(java.lang.String):void, 105, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mMap` via call to `remove`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.mapRemoveBad(java.lang.String):void, 111, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.mMap` via call to `remove`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.mapSubclassWriteBad(java.util.HashMap,java.lang.String):void, 131, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `m` via call to `remove`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.mapSubclassWriteBad(java.util.HashMap,java.lang.String):void, 137, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `m` via call to `remove`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.poolBad():void, 292, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.simplePool` via call to `release`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.poolBad():void, 298, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [Write to container `this.codetoanalyze.java.checkers.Containers.simplePool` via call to `release`]
codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.readSimpleArrayMap():int, 278, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [<Read trace>,Read of container `this.codetoanalyze.java.checkers.Containers.si_map` via call to `get`,<Write trace>,Write to container `this.codetoanalyze.java.checkers.Containers.si_map` via call to `put`] codetoanalyze/java/racerd/Containers.java, codetoanalyze.java.checkers.Containers.readSimpleArrayMap():int, 284, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [<Read trace>,Read of container `this.codetoanalyze.java.checkers.Containers.si_map` via call to `get`,<Write trace>,Write to container `this.codetoanalyze.java.checkers.Containers.si_map` via call to `put`]
codetoanalyze/java/racerd/DeepOwnership.java, DeepOwnership.globalNotOwnedBad():void, 16, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [access to `DeepOwnership.DeepOwnership.global.DeepOwnership.next`] codetoanalyze/java/racerd/DeepOwnership.java, DeepOwnership.globalNotOwnedBad():void, 16, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [access to `DeepOwnership.DeepOwnership.global.DeepOwnership.next`]
codetoanalyze/java/racerd/DeepOwnership.java, DeepOwnership.reassignBaseToGlobalBad():void, 22, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [access to `x.DeepOwnership.next`] codetoanalyze/java/racerd/DeepOwnership.java, DeepOwnership.reassignBaseToGlobalBad():void, 22, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [access to `x.DeepOwnership.next`]
codetoanalyze/java/racerd/Dispatch.java, codetoanalyze.java.checkers.Dispatch.callUnannotatedInterfaceBad(codetoanalyze.java.checkers.UnannotatedInterface):void, 49, INTERFACE_NOT_THREAD_SAFE, no_bucket, ERROR, [Call to un-annotated interface method void UnannotatedInterface.foo()] codetoanalyze/java/racerd/Dispatch.java, codetoanalyze.java.checkers.Dispatch.callUnannotatedInterfaceBad(codetoanalyze.java.checkers.UnannotatedInterface):void, 49, INTERFACE_NOT_THREAD_SAFE, no_bucket, ERROR, [Call to un-annotated interface method void UnannotatedInterface.foo()]

Loading…
Cancel
Save