diff --git a/infer/src/checkers/ThreadSafety.ml b/infer/src/checkers/ThreadSafety.ml index 3637dddba..f8327ce7e 100644 --- a/infer/src/checkers/ThreadSafety.ml +++ b/infer/src/checkers/ThreadSafety.ml @@ -236,7 +236,11 @@ module TransferFunctions (CFG : ProcCfg.S) = struct | "java.lang.ThreadLocal", "get" -> (* ThreadLocal prevents sharing between threads behind the scenes *) true - | _ -> false + | "android.support.v4.util.Pools$SynchronizedPool", "acquire" -> + (* a pool should own all of its objects *) + true + | _ -> + false end | _ -> false in diff --git a/infer/tests/codetoanalyze/java/threadsafety/Containers.java b/infer/tests/codetoanalyze/java/threadsafety/Containers.java index 409c7e6d4..ca0f52273 100644 --- a/infer/tests/codetoanalyze/java/threadsafety/Containers.java +++ b/infer/tests/codetoanalyze/java/threadsafety/Containers.java @@ -20,6 +20,8 @@ import java.util.concurrent.CopyOnWriteArrayList; import javax.annotation.concurrent.ThreadSafe; +import android.support.v4.util.Pools.SynchronizedPool; + class ContainerWrapper { private final List children = new ArrayList(); @@ -152,4 +154,37 @@ class Containers { mContainerWrapper.write(o); } + static SynchronizedPool sPool; + + void poolAcquireOk() { + Obj obj = sPool.acquire(); + obj.f = new Object(); + } + + void poolAcquireThenNullCheckOk() { + Obj obj = sPool.acquire(); + if (obj == null) { + obj = new Obj(); + } + obj.f = new Object(); + } + + // need to understand semantics of release to get this one + void FN_poolReleaseThenWriteBad() { + Obj obj = sPool.acquire(); + sPool.release(obj); + obj.f = new Object(); // should flag + } + + void release(Obj o) { + sPool.release(o); + } + + // we won't catch this without a fancier ownership domain + void FN_poolReleaseThenWriteInterprocBad() { + Obj obj = sPool.acquire(); + release(obj); + obj.f = new Object(); // should flag + } + }