[thread-safety] Add SimplePool as container, mild refactoring of container handling.

Reviewed By: sblackshear

Differential Revision: D5209926

fbshipit-source-id: e886267
master
Kyriakos Nikolaos Gkorogiannis 8 years ago committed by Facebook Github Bot
parent fdad9f552b
commit cfe79cf1ca

@ -329,7 +329,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| ("android.app.Activity" | "android.view.View"), "findViewById" -> | ("android.app.Activity" | "android.view.View"), "findViewById" ->
(* assume findViewById creates fresh View's (note: not always true) *) (* assume findViewById creates fresh View's (note: not always true) *)
true true
| "android.support.v4.util.Pools$SynchronizedPool", "acquire" -> | "android.support.v4.util.Pools$SimplePool", "acquire" ->
(* a pool should own all of its objects *) (* a pool should own all of its objects *)
true true
| _ -> | _ ->
@ -352,51 +352,62 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| "android.support.v4.util.SimpleArrayMap", | "android.support.v4.util.SimpleArrayMap",
("clear" | "ensureCapacity" | "put" | "putAll" | "remove" | "removeAt" ("clear" | "ensureCapacity" | "put" | "putAll" | "remove" | "removeAt"
| "setValueAt") -> true | "setValueAt") -> true
| "android.support.v4.util.Pools$SimplePool",
("acquire" | "release") -> true
| "java.util.List", ("add" | "addAll" | "clear" | "remove" | "set") -> true | "java.util.List", ("add" | "addAll" | "clear" | "remove" | "set") -> true
| "java.util.Map", ("clear" | "put" | "putAll" | "remove") -> true | "java.util.Map", ("clear" | "put" | "putAll" | "remove") -> true
| _ -> false in | _ -> false in
let is_threadsafe_collection typename _ = match Typ.Name.name typename with PatternMatch.supertype_exists tenv is_container_write_ typename
| "java.util.concurrent.ConcurrentMap" | "java.util.concurrent.CopyOnWriteArrayList" ->
true
| _ ->
false in
PatternMatch.supertype_exists tenv is_container_write_ typename &&
not (PatternMatch.supertype_exists tenv is_threadsafe_collection typename)
| _ -> | _ ->
false false
let is_synchronized_container ((_, (base_typ : Typ.t)), accesses) tenv = let is_threadsafe_collection pn tenv = match pn with
let is_annotated_synchronized base_typename container_field tenv = | Typ.Procname.Java java_pname ->
match Tenv.lookup tenv base_typename with let typename = Typ.Name.Java.from_string (Typ.Procname.java_get_class_name java_pname) in
| Some base_typ -> let aux tn _ =
Annotations.field_has_annot match Typ.Name.name tn with
container_field | "java.util.concurrent.ConcurrentMap"
base_typ Annotations.ia_is_synchronized_collection | "java.util.concurrent.CopyOnWriteArrayList"
| None -> | "android.support.v4.util.Pools$SynchronizedPool" -> true
false in | _ -> false in
match List.rev accesses with PatternMatch.supertype_exists tenv aux typename
| AccessPath.FieldAccess base_field :: | _ -> false
AccessPath.FieldAccess container_field :: _->
let base_typename = let is_synchronized_container callee_pname ((_, (base_typ : Typ.t)), accesses) tenv =
Typ.Name.Java.from_string (Fieldname.java_get_class base_field) in if is_threadsafe_collection callee_pname tenv
is_annotated_synchronized base_typename container_field tenv then
| [AccessPath.FieldAccess container_field] -> true
begin else
match base_typ.desc with let is_annotated_synchronized base_typename container_field tenv =
| Typ.Tstruct base_typename | Tptr ({Typ.desc=Tstruct base_typename}, _) -> match Tenv.lookup tenv base_typename with
is_annotated_synchronized base_typename container_field tenv | Some base_typ ->
| _ -> Annotations.field_has_annot
false container_field
end base_typ Annotations.ia_is_synchronized_collection
| _ -> | None ->
false false in
match List.rev accesses with
| AccessPath.FieldAccess base_field ::
AccessPath.FieldAccess container_field :: _->
let base_typename =
Typ.Name.Java.from_string (Fieldname.java_get_class base_field) in
is_annotated_synchronized base_typename container_field tenv
| [AccessPath.FieldAccess container_field] ->
begin
match base_typ.desc with
| Typ.Tstruct base_typename | Tptr ({Typ.desc=Tstruct base_typename}, _) ->
is_annotated_synchronized base_typename container_field tenv
| _ ->
false
end
| _ ->
false
let add_container_write callee_pname receiver_ap callee_loc tenv = let make_container_write callee_pname receiver_ap callee_loc tenv =
(* return true if field pointing to container is marked @SyncrhonizedContainer *)
(* create a dummy write that represents mutating the contents of the container *) (* create a dummy write that represents mutating the contents of the container *)
let open Domain in let open Domain in
let callee_accesses = let callee_accesses =
if is_synchronized_container receiver_ap tenv if is_synchronized_container callee_pname receiver_ap tenv
then then
AccessDomain.empty AccessDomain.empty
else else
@ -420,7 +431,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
failwithf failwithf
"Call to %a is marked as a container write, but has no receiver" "Call to %a is marked as a container write, but has no receiver"
Typ.Procname.pp callee_pname in Typ.Procname.pp callee_pname in
add_container_write callee_pname receiver_ap callee_loc tenv make_container_write callee_pname receiver_ap callee_loc tenv
else else
Summary.read_summary caller_pdesc callee_pname Summary.read_summary caller_pdesc callee_pname

@ -24,6 +24,7 @@ import android.support.v4.util.Pools.SynchronizedPool;
import android.support.v4.util.SparseArrayCompat; import android.support.v4.util.SparseArrayCompat;
import android.util.SparseArray; import android.util.SparseArray;
import android.support.v4.util.SimpleArrayMap; import android.support.v4.util.SimpleArrayMap;
import android.support.v4.util.Pools.SimplePool;
class ContainerWrapper { class ContainerWrapper {
private final List<Object> children = new ArrayList<Object>(); private final List<Object> children = new ArrayList<Object>();
@ -252,5 +253,16 @@ class Containers {
return si_map.get(1); return si_map.get(1);
} }
SimplePool<Integer> simplePool = new SimplePool<Integer>(10);
synchronized public Integer getFromPoolOK() {
return simplePool.acquire();
}
public void poolBad() {
Integer a;
synchronized(this) {
a = simplePool.acquire();
}
simplePool.release(a);
}
} }

@ -38,6 +38,7 @@ codetoanalyze/java/threadsafety/Containers.java, void Containers.mapPutAllBad(Ma
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, [container `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, [container `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, [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/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