[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 *)
global_tenv := Some tenv ;
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"]
(** 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
val pp_per_file : Format.formatter -> per_file -> unit

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

@ -726,8 +726,6 @@ let analyze_procedure {Callbacks.proc_desc; tenv; summary} =
else Payload.update_summary empty_post summary
module AccessListMap = Caml.Map.Make (RacerDDomain.Access)
type conflict = RacerDDomain.TraceElem.t
type report_kind =
@ -1016,6 +1014,81 @@ let empty_reported =
{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.
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
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 RacerDModels in
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}
else reported
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
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
for ObjC_Cpp *)
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 writes *)
let is_cpp_protected_write snapshot =
Typ.Procname.is_java pname || not (AccessSnapshot.is_unprotected snapshot)
in
let is_conflict (snapshot : AccessSnapshot.t) other_thread =
let is_conflict {snapshot; threads= other_threads} =
TraceElem.is_write snapshot.access
&&
if Typ.Procname.is_java pname then
ThreadsDomain.is_any threads || ThreadsDomain.is_any other_thread
else is_cpp_protected_write snapshot
in
let all_writes =
List.filter
~f:(fun {snapshot; threads= other_threads} -> is_conflict snapshot other_threads)
accesses
ThreadsDomain.is_any threads || ThreadsDomain.is_any other_threads
else not (AccessSnapshot.is_unprotected snapshot)
in
if not (List.is_empty all_writes) then (
let conflict = List.hd_exn all_writes in
match List.find ~f:is_conflict accesses with
| None ->
reported_acc
| Some conflict ->
report_thread_safety_violation tenv procdesc
~make_description:(make_read_write_race_description ~read_is_sync:false conflict)
~report_kind:(ReadWriteRace conflict.snapshot.access) snapshot.access threads
wobbly_paths ;
update_reported snapshot.access pname reported_acc )
else reported_acc
| Access.Read _ | ContainerRead _ ->
(* protected read. report unprotected writes and opposite protected writes as conflicts *)
let can_conflict (snapshot1 : AccessSnapshot.t) (snapshot2 : AccessSnapshot.t) =
@ -1181,8 +1247,7 @@ let report_unsafe_accesses (aggregated_access_map : reported_access list AccessL
update_reported snapshot.access pname reported_acc )
else reported_acc
in
AccessListMap.fold
(fun _ (grouped_accesses : reported_access list) reported_acc ->
let report_accesses_on_location (grouped_accesses : reported_access list) reported_acc =
(* reset the reported reads and writes for each memory location *)
let reported =
{ reported_acc with
@ -1195,206 +1260,49 @@ let report_unsafe_accesses (aggregated_access_map : reported_access list AccessL
(* 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) ) )
)
QualifiedCppName.Match.match_qualifiers matcher (Typ.Name.qual_name name) ) ) )
in
let should_report pdesc tenv =
match Procdesc.get_proc_name pdesc with
let should_report {tenv; procdesc} =
match Procdesc.get_proc_name procdesc 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
&& should_report_on_proc procdesc tenv
| ObjC_Cpp objc_cpp ->
(* do not report if a procedure is private *)
Procdesc.get_access pdesc <> PredSymb.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:(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
aux AccessListMap.empty acc_map
end
(* 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 access =
match RacerDDomain.Access.get_access_path access with
| Some (_, path) ->
let check_access_step = function
| AccessPath.ArrayAccess _ ->
false
| AccessPath.FieldAccess fld ->
String.is_substring ~substring:"$SwitchMap" (Typ.Fieldname.to_string fld)
let reportable_accesses = List.filter ~f:should_report grouped_accesses in
List.fold ~f:(report_unsafe_access reportable_accesses) reportable_accesses ~init:reported
in
List.exists path ~f:check_access_step
| None ->
false
ReportMap.fold report_accesses_on_location aggregated_access_map empty_reported |> ignore
(* create a map from [abstraction of a memory loc] -> accesses that
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
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 aggregate_post {threads; accesses; wobbly_paths} tenv procdesc acc =
let aggregate_post tenv procdesc acc {threads; accesses; wobbly_paths} =
AccessDomain.fold
(fun snapshot acc ->
let access_kind = TraceElem.kind snapshot.access in
if should_filter_access access_kind then acc
else
let reported_access : reported_access =
{threads; snapshot; tenv; procdesc; wobbly_paths}
in
AccessListMap.add access_kind reported_access acc )
ReportMap.add reported_access acc )
accesses acc
in
let aggregate_posts acc (tenv, proc_desc) =
match Payload.read proc_desc (Procdesc.get_proc_name proc_desc) with
| Some summary ->
aggregate_post summary tenv proc_desc acc
| None ->
acc
Payload.read proc_desc (Procdesc.get_proc_name proc_desc)
|> Option.fold ~init:acc ~f:(aggregate_post tenv proc_desc)
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
@ -1410,10 +1318,8 @@ let aggregate_by_class file_env =
| _ ->
"unknown"
in
let 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 )
String.Map.update acc classname ~f:(function None -> [proc] | Some bucket -> proc :: bucket)
)
~init:String.Map.empty
@ -1422,12 +1328,6 @@ let aggregate_by_class file_env =
safety *)
let file_analysis {Callbacks.procedures; source_file} =
String.Map.iter
~f:(fun 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) )
~f:(fun class_env -> report_unsafe_accesses (make_results_table class_env))
(aggregate_by_class procedures) ;
IssueLog.store Config.racerd_issues_dir_name source_file

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

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

@ -88,8 +88,14 @@ class Containers {
mListNobodyWrites.size();
}
List mListSyncWrites;
synchronized void listSyncAddBad(String s) {
mListSyncWrites.add(s);
}
boolean listReadBad(String s) {
return mList.contains(s);
return mListSyncWrites.contains(s);
}
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, 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/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.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.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.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.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, 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, 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, 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.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.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.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.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.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.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.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.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.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.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.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, 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, 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, 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, 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, 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, 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.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()]

Loading…
Cancel
Save