[thread-safety] make a distinguished access kind for container writes

Summary:
The way we represented container writes before was pretty hacky: just use a dummy field for the name of the method that performs the container write.
This diff introduces a new access kind for container writes that is much more structured.
This will make it easier to soundly handle aliasing between containers and support container reads in the near future.

Reviewed By: da319

Differential Revision: D5465747

fbshipit-source-id: e021ec2
master
Sam Blackshear 8 years ago committed by Facebook Github Bot
parent f49d292c3b
commit 2dcde3a812

@ -25,35 +25,6 @@ let is_owned access_path attribute_map =
ThreadSafetyDomain.AttributeMapDomain.has_attribute access_path ThreadSafetyDomain.AttributeMapDomain.has_attribute access_path
ThreadSafetyDomain.Attribute.unconditionally_owned attribute_map ThreadSafetyDomain.Attribute.unconditionally_owned attribute_map
let container_write_string = "infer.dummy.__CONTAINERWRITE__"
(* return (name of container, name of mutating function call) pair *)
let get_container_write_desc sink =
match ThreadSafetyDomain.TraceElem.kind sink with
| Write ((base_var, _), access_list)
-> (
let get_container_write_desc_ call_name container_name =
match
String.chop_prefix (Typ.Fieldname.to_string call_name) ~prefix:container_write_string
with
| Some call_name
-> Some (container_name, call_name)
| None
-> None
in
match List.rev access_list with
| (FieldAccess call_name) :: (FieldAccess container_name) :: _
-> get_container_write_desc_ call_name (Typ.Fieldname.to_string container_name)
| [(FieldAccess call_name)]
-> get_container_write_desc_ call_name (F.asprintf "%a" Var.pp base_var)
| _
-> None )
| Read _ | InterfaceCall _
-> (* TODO: support Read *)
None
let is_container_write_sink sink = Option.is_some (get_container_write_desc sink)
(*Bit of redundancy with code in is_unprotected, might alter later *) (*Bit of redundancy with code in is_unprotected, might alter later *)
let make_excluder locks threads = let make_excluder locks threads =
if locks && not threads then ThreadSafetyDomain.Excluder.Lock if locks && not threads then ThreadSafetyDomain.Excluder.Lock
@ -497,15 +468,9 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
let callee_accesses = let callee_accesses =
if is_synchronized_container callee_pname receiver_ap tenv then AccessDomain.empty if is_synchronized_container callee_pname receiver_ap tenv then AccessDomain.empty
else else
let dummy_fieldname = let container_access = make_container_access receiver_ap callee_pname in
Typ.Fieldname.Java.from_string AccessDomain.add_access (Unprotected (Some 0)) (container_access ~is_write:true callee_loc)
(container_write_string ^ Typ.Procname.get_method callee_pname) AccessDomain.empty
in
let dummy_access_ap =
(fst receiver_ap, snd receiver_ap @ [AccessPath.FieldAccess dummy_fieldname])
in
AccessDomain.add_access (Unprotected (Some 0))
(make_field_access dummy_access_ap ~is_write:true callee_loc) AccessDomain.empty
in in
(* TODO: for now all formals escape *) (* TODO: for now all formals escape *)
(* we need a more intelligent escape analysis, that branches on whether (* we need a more intelligent escape analysis, that branches on whether
@ -1036,12 +1001,17 @@ let analyze_procedure {Callbacks.proc_desc; tenv; summary} =
else Summary.update_summary empty_post summary else Summary.update_summary empty_post summary
module AccessListMap = Caml.Map.Make (struct module AccessListMap = Caml.Map.Make (struct
type t = AccessPath.Raw.t option type t = ThreadSafetyDomain.Access.t
(* TODO -- keep this compare to satisfy the order of tests, consider using Raw.compare *) (* TODO -- keep this compare to satisfy the order of tests, consider using Raw.compare *)
let compare = let compare access1 access2 =
Option.compare (fun access_path1 access_path2 -> let open ThreadSafetyDomain in
List.compare AccessPath.compare_access (snd access_path1) (snd access_path2) ) match (access1, access2) with
| ( (Access.Read access_path1 | Write access_path1)
, (Access.Read access_path2 | Write access_path2) )
-> List.compare AccessPath.compare_access (snd access_path1) (snd access_path2)
| _
-> Access.compare access1 access2
end) end)
let get_current_class_and_threadsafe_superclasses tenv pname = let get_current_class_and_threadsafe_superclasses tenv pname =
@ -1086,33 +1056,33 @@ let get_all_accesses_with_pre pre_filter access_filter accesses =
let get_all_accesses = get_all_accesses_with_pre (fun _ -> true) let get_all_accesses = get_all_accesses_with_pre (fun _ -> true)
let pp_container_access fmt (container_name, function_name) = let pp_container_access fmt (access_path, access_pname) =
F.fprintf fmt "container %s via call to %s" (MF.monospaced_to_string container_name) F.fprintf fmt "container %a via call to %s" (MF.wrap_monospaced AccessPath.Raw.pp) access_path
(MF.monospaced_to_string function_name) (MF.monospaced_to_string (Typ.Procname.get_method access_pname))
let pp_access fmt sink = let pp_access fmt sink =
match get_container_write_desc sink with match ThreadSafetyDomain.PathDomain.Sink.kind sink with
| Some container_write_desc | Read access_path | Write access_path
-> pp_container_access fmt container_write_desc -> F.fprintf fmt "%a" (MF.wrap_monospaced AccessPath.pp_access_list) (snd access_path)
| None -> | ContainerWrite (access_path, access_pname)
match ThreadSafetyDomain.PathDomain.Sink.kind sink with -> pp_container_access fmt (access_path, access_pname)
| Read access_path | Write access_path | InterfaceCall _ as access
-> F.fprintf fmt "%a" (MF.wrap_monospaced AccessPath.pp_access_list) (snd access_path) -> F.fprintf fmt "%a" ThreadSafetyDomain.Access.pp access
| InterfaceCall _ as access
-> F.fprintf fmt "%a" ThreadSafetyDomain.Access.pp access
let desc_of_sink sink = let desc_of_sink sink =
match get_container_write_desc sink with let sink_pname = CallSite.pname (ThreadSafetyDomain.PathDomain.Sink.call_site sink) in
| Some container_write_desc match ThreadSafetyDomain.PathDomain.Sink.kind sink with
-> F.asprintf "%a" pp_container_access container_write_desc | Read _ | Write _
| None -> if Typ.Procname.equal sink_pname Typ.Procname.empty_block then
-> let sink_pname = CallSite.pname (ThreadSafetyDomain.PathDomain.Sink.call_site sink) in F.asprintf "access to %a" pp_access sink
if Typ.Procname.equal sink_pname Typ.Procname.empty_block then else F.asprintf "call to %a" Typ.Procname.pp sink_pname
match ThreadSafetyDomain.PathDomain.Sink.kind sink with | ContainerWrite (access_path, access_pname)
| Read _ | Write _ -> if Typ.Procname.equal sink_pname access_pname then
-> F.asprintf "access to %a" pp_access sink F.asprintf "Write to %a" pp_container_access (access_path, access_pname)
| InterfaceCall interface_pname else F.asprintf "call to %a" Typ.Procname.pp sink_pname
-> F.asprintf "call to %a" Typ.Procname.pp interface_pname | InterfaceCall _ as access
-> if Typ.Procname.equal sink_pname Typ.Procname.empty_block then
F.asprintf "%a1" ThreadSafetyDomain.Access.pp access
else F.asprintf "call to %a" Typ.Procname.pp sink_pname else F.asprintf "call to %a" Typ.Procname.pp sink_pname
let trace_of_pname orig_sink orig_pdesc callee_pname = let trace_of_pname orig_sink orig_pdesc callee_pname =
@ -1196,7 +1166,8 @@ let make_unprotected_write_description tenv pname final_sink_site initial_sink_s
Format.asprintf "Unprotected write. Non-private method %a%s %s %a outside of synchronization.%s" Format.asprintf "Unprotected write. Non-private method %a%s %s %a outside of synchronization.%s"
(MF.wrap_monospaced pp_procname_short) pname (MF.wrap_monospaced pp_procname_short) pname
(if CallSite.equal final_sink_site initial_sink_site then "" else " indirectly") (if CallSite.equal final_sink_site initial_sink_site then "" else " indirectly")
(if is_container_write_sink final_sink then "mutates" else "writes to field") ( if ThreadSafetyDomain.TraceElem.is_container_write final_sink then "mutates"
else "writes to field" )
pp_access final_sink (calculate_addendum_message tenv pname) pp_access final_sink (calculate_addendum_message tenv pname)
let make_read_write_race_description conflicts tenv pname final_sink_site initial_sink_site let make_read_write_race_description conflicts tenv pname final_sink_site initial_sink_site
@ -1282,7 +1253,7 @@ let report_unsafe_accesses aggregated_access_map =
CallSite.Set.mem (TraceElem.call_site access) reported_sites CallSite.Set.mem (TraceElem.call_site access) reported_sites
|| ||
match TraceElem.kind access with match TraceElem.kind access with
| Access.Write _ | Access.Write _ | Access.ContainerWrite _
-> Typ.Procname.Set.mem pname reported_writes -> Typ.Procname.Set.mem pname reported_writes
| Access.Read _ | Access.Read _
-> Typ.Procname.Set.mem pname reported_reads -> Typ.Procname.Set.mem pname reported_reads
@ -1292,7 +1263,7 @@ let report_unsafe_accesses aggregated_access_map =
let update_reported access pname reported = let update_reported access pname reported =
let reported_sites = CallSite.Set.add (TraceElem.call_site access) reported.reported_sites in let reported_sites = CallSite.Set.add (TraceElem.call_site access) reported.reported_sites in
match TraceElem.kind access with match TraceElem.kind access with
| Access.Write _ | Access.Write _ | Access.ContainerWrite _
-> let reported_writes = Typ.Procname.Set.add pname reported.reported_writes in -> let reported_writes = Typ.Procname.Set.add pname reported.reported_writes in
{reported with reported_writes; reported_sites} {reported with reported_writes; reported_sites}
| Access.Read _ | Access.Read _
@ -1312,7 +1283,7 @@ let report_unsafe_accesses aggregated_access_map =
| Access.InterfaceCall _, AccessPrecondition.Protected _ | Access.InterfaceCall _, AccessPrecondition.Protected _
-> (* un-annotated interface call, but it's protected by a lock/thread. don't report *) -> (* un-annotated interface call, but it's protected by a lock/thread. don't report *)
reported_acc reported_acc
| Access.Write _, AccessPrecondition.Unprotected _ -> ( | (Access.Write _ | ContainerWrite _), AccessPrecondition.Unprotected _ -> (
match Procdesc.get_proc_name pdesc with match Procdesc.get_proc_name pdesc with
| Java _ | Java _
-> if threaded then reported_acc -> if threaded then reported_acc
@ -1324,7 +1295,7 @@ let report_unsafe_accesses aggregated_access_map =
| _ | _
-> (* Do not report unprotected writes for ObjC_Cpp *) -> (* Do not report unprotected writes for ObjC_Cpp *)
reported_acc ) reported_acc )
| Access.Write _, AccessPrecondition.Protected _ | (Access.Write _ | ContainerWrite _), AccessPrecondition.Protected _
-> (* protected write, do nothing *) -> (* protected write, do nothing *)
reported_acc reported_acc
| Access.Read _, AccessPrecondition.Unprotected _ | Access.Read _, AccessPrecondition.Unprotected _
@ -1478,31 +1449,25 @@ let quotient_access_map acc_map =
let rec aux acc m = let rec aux acc m =
if AccessListMap.is_empty m then acc if AccessListMap.is_empty m then acc
else else
let k_opt, vals = AccessListMap.choose m in let k, vals = AccessListMap.choose m in
let _, _, _, tenv, _ = let _, _, _, tenv, _ =
List.find_exn vals ~f:(fun (elem, _, _, _, _) -> List.find_exn vals ~f:(fun (elem, _, _, _, _) ->
Option.equal ThreadSafetyDomain.Access.equal (ThreadSafetyDomain.TraceElem.kind elem) k )
(fun e1 e2 -> AccessPath.Raw.equal e1 e2)
k_opt
(ThreadSafetyDomain.Access.get_access_path (ThreadSafetyDomain.TraceElem.kind elem))
)
in in
(* assumption: the tenv for k is sufficient for k' too *) (* assumption: the tenv for k is sufficient for k' too *)
let k_part, non_k_part = let k_part, non_k_part =
AccessListMap.partition AccessListMap.partition
(fun k_opt' _ -> (fun k' _ ->
match (k_opt', k_opt) with match (k, k') with
| Some k', Some k | (Read ap1 | Write ap1), (Read ap2 | Write ap2)
-> may_alias tenv k k' -> may_alias tenv ap1 ap2
| None, None
-> true
| _ | _
-> false) -> ThreadSafetyDomain.Access.equal k k')
m m
in in
if AccessListMap.is_empty k_part then failwith "may_alias is not reflexive!" ; if AccessListMap.is_empty k_part then failwith "may_alias is not reflexive!" ;
let k_accesses = AccessListMap.fold (fun _ v acc' -> List.append v acc') k_part [] in let k_accesses = AccessListMap.fold (fun _ v acc' -> List.append v acc') k_part [] in
let new_acc = AccessListMap.add k_opt k_accesses acc in let new_acc = AccessListMap.add k k_accesses acc in
aux new_acc non_k_part aux new_acc non_k_part
in in
aux AccessListMap.empty acc_map aux AccessListMap.empty acc_map
@ -1510,14 +1475,18 @@ let quotient_access_map acc_map =
(* decide if we should throw away a path before doing safety analysis (* 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 for now, just check for whether the access is within a switch-map
that is auto-generated by Java. *) that is auto-generated by Java. *)
let should_filter_access (_, path) = let should_filter_access access =
let check_access_step = function match ThreadSafetyDomain.Access.get_access_path access with
| AccessPath.ArrayAccess _ | Some (_, path)
-> false -> let check_access_step = function
| AccessPath.FieldAccess fld | AccessPath.ArrayAccess _
-> String.is_substring ~substring:"$SwitchMap" (Typ.Fieldname.to_string fld) -> false
in | AccessPath.FieldAccess fld
List.exists path ~f:check_access_step -> String.is_substring ~substring:"$SwitchMap" (Typ.Fieldname.to_string fld)
in
List.exists path ~f:check_access_step
| None
-> false
(* create a map from [abstraction of a memory loc] -> accesses that may touch that memory loc. for (* 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 now, our abstraction is an access path like x.f.g whose concretization is the set of memory cells
@ -1529,14 +1498,14 @@ let make_results_table file_env =
(fun pre accesses acc -> (fun pre accesses acc ->
PathDomain.Sinks.fold PathDomain.Sinks.fold
(fun access acc -> (fun access acc ->
let access_path_opt = Access.get_access_path (TraceElem.kind access) in let access_kind = TraceElem.kind access in
if Option.exists ~f:should_filter_access access_path_opt then acc if should_filter_access access_kind then acc
else else
let grouped_accesses = let grouped_accesses =
try AccessListMap.find access_path_opt acc try AccessListMap.find access_kind acc
with Not_found -> [] with Not_found -> []
in in
AccessListMap.add access_path_opt AccessListMap.add access_kind
((access, pre, threaded, tenv, pdesc) :: grouped_accesses) acc) ((access, pre, threaded, tenv, pdesc) :: grouped_accesses) acc)
(PathDomain.sinks accesses) acc) (PathDomain.sinks accesses) acc)
accesses acc accesses acc

@ -14,6 +14,7 @@ module Access = struct
type t = type t =
| Read of AccessPath.Raw.t | Read of AccessPath.Raw.t
| Write of AccessPath.Raw.t | Write of AccessPath.Raw.t
| ContainerWrite of AccessPath.Raw.t * Typ.Procname.t
| InterfaceCall of Typ.Procname.t | InterfaceCall of Typ.Procname.t
[@@deriving compare] [@@deriving compare]
@ -21,16 +22,21 @@ module Access = struct
if is_write then Write access_path else Read access_path if is_write then Write access_path else Read access_path
let get_access_path = function let get_access_path = function
| Read access_path | Write access_path | Read access_path | Write access_path | ContainerWrite (access_path, _)
-> Some access_path -> Some access_path
| InterfaceCall _ | InterfaceCall _
-> None -> None
let equal t1 t2 = Int.equal (compare t1 t2) 0
let pp fmt = function let pp fmt = function
| Read access_path | Read access_path
-> F.fprintf fmt "Read of %a" AccessPath.Raw.pp access_path -> F.fprintf fmt "Read of %a" AccessPath.Raw.pp access_path
| Write access_path | Write access_path
-> F.fprintf fmt "Write to %a" AccessPath.Raw.pp access_path -> F.fprintf fmt "Write to %a" AccessPath.Raw.pp access_path
| ContainerWrite (access_path, pname)
-> F.fprintf fmt "Write to container %a via %a" AccessPath.Raw.pp access_path Typ.Procname.pp
pname
| InterfaceCall pname | InterfaceCall pname
-> F.fprintf fmt "Call to un-annotated interface method %a" Typ.Procname.pp pname -> F.fprintf fmt "Call to un-annotated interface method %a" Typ.Procname.pp pname
end end
@ -40,12 +46,11 @@ module TraceElem = struct
type t = {site: CallSite.t; kind: Kind.t} [@@deriving compare] type t = {site: CallSite.t; kind: Kind.t} [@@deriving compare]
let is_read {kind} = match kind with Read _ -> true | InterfaceCall _ | Write _ -> false let is_write {kind} =
match kind with InterfaceCall _ | Read _ -> false | ContainerWrite _ | Write _ -> true
let is_write {kind} = match kind with InterfaceCall _ | Read _ -> false | Write _ -> true
let is_interface_call {kind} = let is_container_write {kind} =
match kind with InterfaceCall _ -> true | Read _ | Write _ -> false match kind with InterfaceCall _ | Read _ | Write _ -> false | ContainerWrite _ -> true
let call_site {site} = site let call_site {site} = site
@ -66,6 +71,10 @@ module TraceElem = struct
end) end)
end end
let make_container_access access_path pname ~is_write:_ loc =
let site = CallSite.make Typ.Procname.empty_block loc in
TraceElem.make (Access.ContainerWrite (access_path, pname)) site
let make_field_access access_path ~is_write loc = let make_field_access access_path ~is_write loc =
let site = CallSite.make Typ.Procname.empty_block loc in let site = CallSite.make Typ.Procname.empty_block loc in
TraceElem.make (Access.make_field_access access_path ~is_write) site TraceElem.make (Access.make_field_access access_path ~is_write) site

@ -12,14 +12,17 @@ module F = Format
module Access : sig module Access : sig
type t = type t =
| Read of AccessPath.Raw.t (** Field read *) | Read of AccessPath.Raw.t (** Field or array read *)
| Write of AccessPath.Raw.t (** Field write *) | Write of AccessPath.Raw.t (** Field or array write *)
| ContainerWrite of AccessPath.Raw.t * Typ.Procname.t (** Write to container object *)
| InterfaceCall of Typ.Procname.t | InterfaceCall of Typ.Procname.t
(** Call to method of interface not annotated with @ThreadSafe *) (** Call to method of interface not annotated with @ThreadSafe *)
[@@deriving compare] [@@deriving compare]
val get_access_path : t -> AccessPath.Raw.t option val get_access_path : t -> AccessPath.Raw.t option
val equal : t -> t -> bool
val pp : F.formatter -> t -> unit val pp : F.formatter -> t -> unit
end end
@ -28,9 +31,7 @@ module TraceElem : sig
val is_write : t -> bool val is_write : t -> bool
val is_read : t -> bool val is_container_write : t -> bool
val is_interface_call : t -> bool
end end
(** A bool that is true if a lock is definitely held. Note that this is unsound because it assumes (** A bool that is true if a lock is definitely held. Note that this is unsound because it assumes
@ -178,6 +179,9 @@ type summary =
include AbstractDomain.WithBottom with type astate := astate include AbstractDomain.WithBottom with type astate := astate
val make_container_access :
AccessPath.Raw.t -> Typ.Procname.t -> is_write:bool -> Location.t -> TraceElem.t
val make_field_access : AccessPath.Raw.t -> is_write:bool -> Location.t -> TraceElem.t val make_field_access : AccessPath.Raw.t -> is_write:bool -> Location.t -> TraceElem.t
val make_unannotated_call_access : Typ.Procname.t -> Location.t -> TraceElem.t val make_unannotated_call_access : Typ.Procname.t -> Location.t -> TraceElem.t

@ -21,24 +21,24 @@ codetoanalyze/java/threadsafety/Builders.java, void TopLevelBuilder.setG(String)
codetoanalyze/java/threadsafety/Constructors.java, Constructors Constructors.singletonBad(), 2, THREAD_SAFETY_VIOLATION, [call to Constructors.<init>(Object),access to `Constructors.staticField`] codetoanalyze/java/threadsafety/Constructors.java, Constructors Constructors.singletonBad(), 2, THREAD_SAFETY_VIOLATION, [call to Constructors.<init>(Object),access to `Constructors.staticField`]
codetoanalyze/java/threadsafety/Constructors.java, Constructors.<init>(), 1, THREAD_SAFETY_VIOLATION, [access to `Constructors.staticField`] codetoanalyze/java/threadsafety/Constructors.java, Constructors.<init>(), 1, THREAD_SAFETY_VIOLATION, [access to `Constructors.staticField`]
codetoanalyze/java/threadsafety/Constructors.java, Constructors.<init>(Constructors), 1, THREAD_SAFETY_VIOLATION, [access to `Constructors.field`] codetoanalyze/java/threadsafety/Constructors.java, Constructors.<init>(Constructors), 1, THREAD_SAFETY_VIOLATION, [access to `Constructors.field`]
codetoanalyze/java/threadsafety/Containers.java, void Containers.addToSimpleArrayMapBad(SimpleArrayMap), 1, THREAD_SAFETY_VIOLATION, [container `&map` via call to `put`] codetoanalyze/java/threadsafety/Containers.java, void Containers.addToSimpleArrayMapBad(SimpleArrayMap), 1, THREAD_SAFETY_VIOLATION, [Write to container `&map` via call to `put`]
codetoanalyze/java/threadsafety/Containers.java, void Containers.addToSparseArrayBad(SparseArray), 1, THREAD_SAFETY_VIOLATION, [container `&sparseArray` via call to `put`] codetoanalyze/java/threadsafety/Containers.java, void Containers.addToSparseArrayBad(SparseArray), 1, THREAD_SAFETY_VIOLATION, [Write to container `&sparseArray` via call to `put`]
codetoanalyze/java/threadsafety/Containers.java, void Containers.addToSparseArrayCompatBad(SparseArrayCompat), 1, THREAD_SAFETY_VIOLATION, [container `&sparseArray` via call to `put`] codetoanalyze/java/threadsafety/Containers.java, void Containers.addToSparseArrayCompatBad(SparseArrayCompat), 1, THREAD_SAFETY_VIOLATION, [Write to container `&sparseArray` via call to `put`]
codetoanalyze/java/threadsafety/Containers.java, void Containers.containerWrapperUnownedWriteBad(Object), 1, THREAD_SAFETY_VIOLATION, [container `codetoanalyze.java.checkers.ContainerWrapper.children` via call to `add`,container `codetoanalyze.java.checkers.ContainerWrapper.children` via call to `add`,container `codetoanalyze.java.checkers.ContainerWrapper.children` via call to `add`] codetoanalyze/java/threadsafety/Containers.java, void Containers.containerWrapperUnownedWriteBad(Object), 1, THREAD_SAFETY_VIOLATION, [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/threadsafety/Containers.java, void Containers.listAddAllBad(Collection), 1, THREAD_SAFETY_VIOLATION, [container `codetoanalyze.java.checkers.Containers.mList` via call to `addAll`] codetoanalyze/java/threadsafety/Containers.java, void Containers.listAddAllBad(Collection), 1, THREAD_SAFETY_VIOLATION, [Write to container `&this.codetoanalyze.java.checkers.Containers.mList` via call to `addAll`]
codetoanalyze/java/threadsafety/Containers.java, void Containers.listAddBad1(String), 1, THREAD_SAFETY_VIOLATION, [container `codetoanalyze.java.checkers.Containers.mList` via call to `add`] codetoanalyze/java/threadsafety/Containers.java, void Containers.listAddBad1(String), 1, THREAD_SAFETY_VIOLATION, [Write to container `&this.codetoanalyze.java.checkers.Containers.mList` via call to `add`]
codetoanalyze/java/threadsafety/Containers.java, void Containers.listAddBad2(int,String), 1, THREAD_SAFETY_VIOLATION, [container `codetoanalyze.java.checkers.Containers.mList` via call to `add`] codetoanalyze/java/threadsafety/Containers.java, void Containers.listAddBad2(int,String), 1, THREAD_SAFETY_VIOLATION, [Write to container `&this.codetoanalyze.java.checkers.Containers.mList` via call to `add`]
codetoanalyze/java/threadsafety/Containers.java, void Containers.listClearBad(), 1, THREAD_SAFETY_VIOLATION, [container `codetoanalyze.java.checkers.Containers.mList` via call to `clear`] codetoanalyze/java/threadsafety/Containers.java, void Containers.listClearBad(), 1, THREAD_SAFETY_VIOLATION, [Write to container `&this.codetoanalyze.java.checkers.Containers.mList` via call to `clear`]
codetoanalyze/java/threadsafety/Containers.java, void Containers.listRemoveBad1(int), 1, THREAD_SAFETY_VIOLATION, [container `codetoanalyze.java.checkers.Containers.mList` via call to `remove`] codetoanalyze/java/threadsafety/Containers.java, void Containers.listRemoveBad1(int), 1, THREAD_SAFETY_VIOLATION, [Write to container `&this.codetoanalyze.java.checkers.Containers.mList` via call to `remove`]
codetoanalyze/java/threadsafety/Containers.java, void Containers.listRemoveBad2(String), 1, THREAD_SAFETY_VIOLATION, [container `codetoanalyze.java.checkers.Containers.mList` via call to `remove`] codetoanalyze/java/threadsafety/Containers.java, void Containers.listRemoveBad2(String), 1, THREAD_SAFETY_VIOLATION, [Write to container `&this.codetoanalyze.java.checkers.Containers.mList` via call to `remove`]
codetoanalyze/java/threadsafety/Containers.java, void Containers.listSetBad(int,String), 1, THREAD_SAFETY_VIOLATION, [container `codetoanalyze.java.checkers.Containers.mList` via call to `set`] codetoanalyze/java/threadsafety/Containers.java, void Containers.listSetBad(int,String), 1, THREAD_SAFETY_VIOLATION, [Write to container `&this.codetoanalyze.java.checkers.Containers.mList` via call to `set`]
codetoanalyze/java/threadsafety/Containers.java, void Containers.listSubclassWriteBad(ArrayList,int), 1, THREAD_SAFETY_VIOLATION, [container `&list` via call to `remove`] codetoanalyze/java/threadsafety/Containers.java, void Containers.listSubclassWriteBad(ArrayList,int), 1, THREAD_SAFETY_VIOLATION, [Write to container `&list` via call to `remove`]
codetoanalyze/java/threadsafety/Containers.java, void Containers.mapClearBad(), 1, THREAD_SAFETY_VIOLATION, [container `codetoanalyze.java.checkers.Containers.mMap` via call to `clear`] codetoanalyze/java/threadsafety/Containers.java, void Containers.mapClearBad(), 1, THREAD_SAFETY_VIOLATION, [Write to container `&this.codetoanalyze.java.checkers.Containers.mMap` via call to `clear`]
codetoanalyze/java/threadsafety/Containers.java, void Containers.mapPutAllBad(Map), 1, THREAD_SAFETY_VIOLATION, [container `codetoanalyze.java.checkers.Containers.mMap` via call to `putAll`] codetoanalyze/java/threadsafety/Containers.java, void Containers.mapPutAllBad(Map), 1, THREAD_SAFETY_VIOLATION, [Write to container `&this.codetoanalyze.java.checkers.Containers.mMap` via call to `putAll`]
codetoanalyze/java/threadsafety/Containers.java, void Containers.mapPutBad(String,String), 1, THREAD_SAFETY_VIOLATION, [container `codetoanalyze.java.checkers.Containers.mMap` via call to `put`] codetoanalyze/java/threadsafety/Containers.java, void Containers.mapPutBad(String,String), 1, THREAD_SAFETY_VIOLATION, [Write to container `&this.codetoanalyze.java.checkers.Containers.mMap` via call to `put`]
codetoanalyze/java/threadsafety/Containers.java, void Containers.mapRemoveBad(String), 1, THREAD_SAFETY_VIOLATION, [container `codetoanalyze.java.checkers.Containers.mMap` via call to `remove`] codetoanalyze/java/threadsafety/Containers.java, void Containers.mapRemoveBad(String), 1, THREAD_SAFETY_VIOLATION, [Write to container `&this.codetoanalyze.java.checkers.Containers.mMap` via call to `remove`]
codetoanalyze/java/threadsafety/Containers.java, void Containers.mapSubclassWriteBad(HashMap,String), 1, THREAD_SAFETY_VIOLATION, [container `&m` via call to `remove`] codetoanalyze/java/threadsafety/Containers.java, void Containers.mapSubclassWriteBad(HashMap,String), 1, THREAD_SAFETY_VIOLATION, [Write to container `&m` via call to `remove`]
codetoanalyze/java/threadsafety/Containers.java, void Containers.poolBad(), 5, THREAD_SAFETY_VIOLATION, [container `codetoanalyze.java.checkers.Containers.simplePool` via call to `release`] codetoanalyze/java/threadsafety/Containers.java, void Containers.poolBad(), 5, THREAD_SAFETY_VIOLATION, [Write to container `&this.codetoanalyze.java.checkers.Containers.simplePool` via call to `release`]
codetoanalyze/java/threadsafety/DeDup.java, void DeDup.colocated_read_write(), 1, THREAD_SAFETY_VIOLATION, [<Beginning of read trace>,call to void DeDup.read_and_write(),access to `codetoanalyze.java.checkers.DeDup.colocated_read`,<Beginning of write trace>,access to `codetoanalyze.java.checkers.DeDup.colocated_read`] codetoanalyze/java/threadsafety/DeDup.java, void DeDup.colocated_read_write(), 1, THREAD_SAFETY_VIOLATION, [<Beginning of read trace>,call to void DeDup.read_and_write(),access to `codetoanalyze.java.checkers.DeDup.colocated_read`,<Beginning of write trace>,access to `codetoanalyze.java.checkers.DeDup.colocated_read`]
codetoanalyze/java/threadsafety/DeDup.java, void DeDup.separate_write_to_colocated_read(), 1, THREAD_SAFETY_VIOLATION, [access to `codetoanalyze.java.checkers.DeDup.colocated_read`] codetoanalyze/java/threadsafety/DeDup.java, void DeDup.separate_write_to_colocated_read(), 1, THREAD_SAFETY_VIOLATION, [access to `codetoanalyze.java.checkers.DeDup.colocated_read`]
codetoanalyze/java/threadsafety/DeDup.java, void DeDup.twoWritesOneInCaller(), 2, THREAD_SAFETY_VIOLATION, [access to `codetoanalyze.java.checkers.DeDup.field`] codetoanalyze/java/threadsafety/DeDup.java, void DeDup.twoWritesOneInCaller(), 2, THREAD_SAFETY_VIOLATION, [access to `codetoanalyze.java.checkers.DeDup.field`]

Loading…
Cancel
Save