From 0a06353bcea6a6c51ec22619ceaf9ade49437fdc Mon Sep 17 00:00:00 2001 From: Nikos Gorogiannis Date: Thu, 17 Oct 2019 02:55:28 -0700 Subject: [PATCH] [starvation] more tests documenting interaction with thread status Summary: As per title. These test pass already because the previous thread domain was sufficient to express them. This won't necessarily be true when the whole-program analysis version comes around, because we may decide to not report on the `Threaded` elements (see domain). Reviewed By: dulmarod Differential Revision: D17930653 fbshipit-source-id: 2174f6b22 --- .../java/starvation/ThreadDeadlock.java | 82 +++++++++++++++++++ .../java/starvation/UIDeadlock.java | 39 --------- .../codetoanalyze/java/starvation/issues.exp | 8 +- 3 files changed, 88 insertions(+), 41 deletions(-) create mode 100644 infer/tests/codetoanalyze/java/starvation/ThreadDeadlock.java delete mode 100644 infer/tests/codetoanalyze/java/starvation/UIDeadlock.java diff --git a/infer/tests/codetoanalyze/java/starvation/ThreadDeadlock.java b/infer/tests/codetoanalyze/java/starvation/ThreadDeadlock.java new file mode 100644 index 000000000..75c4315b7 --- /dev/null +++ b/infer/tests/codetoanalyze/java/starvation/ThreadDeadlock.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import android.support.annotation.UiThread; +import android.support.annotation.WorkerThread; + +class ThreadDeadlock { + Object lockA; + + // methods cannot run in parallel because both are on UI thread, thus no deadlock + + @UiThread + public synchronized void noParallelismAOk() { + synchronized (lockA) { + } + } + + @UiThread + public void noParallelismBOk() { + synchronized (lockA) { + synchronized (this) { + } + } + } + + Object lockB; + + // deadlock, one method on UI thread, one on Worker thread + + @UiThread + public synchronized void annotatedUiThreadBad() { + synchronized (lockB) { + } + } + + @WorkerThread + public void annotatedWorkerThreadBad() { + synchronized (lockB) { + synchronized (this) { + } + } + } + + Object lockC; + + // deadlock as above, but here assertions are used to determine thread status + + public synchronized void assertOnUIThreadBad() { + OurThreadUtils.assertOnUiThread(); + synchronized (lockC) { + } + } + + public void assertOnBackgroundThreadBad() { + OurThreadUtils.assertOnBackgroundThread(); + synchronized (lockC) { + synchronized (this) { + } + } + } + + Object lockD; + + // deadlock as above, though less certain because the only hint of concurrency is that + // methods take locks + + public synchronized void notAnnotatedBadA() { + synchronized (lockD) { + } + } + + public void notAnnotatedBBad() { + synchronized (lockD) { + synchronized (this) { + } + } + } +} diff --git a/infer/tests/codetoanalyze/java/starvation/UIDeadlock.java b/infer/tests/codetoanalyze/java/starvation/UIDeadlock.java deleted file mode 100644 index da237fe4c..000000000 --- a/infer/tests/codetoanalyze/java/starvation/UIDeadlock.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import android.support.annotation.UiThread; - -class UIDeadlock { - Object lockA, lockB; - - @UiThread - public synchronized void onUIThreadAOk() { - synchronized (lockA) { - } - } - - @UiThread - public void onUIThreadBOk() { - synchronized (lockA) { - synchronized (this) { - } - } - } - - @UiThread - public synchronized void onUIThreadBad() { - synchronized (lockB) { - } - } - - public void notOnUIThreadBad() { - synchronized (lockB) { - synchronized (this) { - } - } - } -} diff --git a/infer/tests/codetoanalyze/java/starvation/issues.exp b/infer/tests/codetoanalyze/java/starvation/issues.exp index 8e54d8df1..98e05cd70 100644 --- a/infer/tests/codetoanalyze/java/starvation/issues.exp +++ b/infer/tests/codetoanalyze/java/starvation/issues.exp @@ -67,12 +67,16 @@ codetoanalyze/java/starvation/StrictModeViolation.java, StrictModeViolation.viol codetoanalyze/java/starvation/StrictModeViolation.java, StrictModeViolation.violateStrictModeBad():void, 38, STRICT_MODE_VIOLATION, no_bucket, ERROR, [`void StrictModeViolation.violateStrictModeBad()`,calls `boolean File.setReadOnly()`] codetoanalyze/java/starvation/StrictModeViolation.java, StrictModeViolation.violateStrictModeBad():void, 39, STRICT_MODE_VIOLATION, no_bucket, ERROR, [`void StrictModeViolation.violateStrictModeBad()`,calls `boolean File.setWritable(boolean)`] codetoanalyze/java/starvation/SuppLint.java, SuppLint.onUiThreadBad():void, 25, STARVATION, no_bucket, ERROR, [`void SuppLint.onUiThreadBad()`,calls `Object Future.get()`] +codetoanalyze/java/starvation/ThreadDeadlock.java, ThreadDeadlock.annotatedUiThreadBad():void, 35, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void ThreadDeadlock.annotatedUiThreadBad()`, locks `this` in `class ThreadDeadlock`, locks `this.lockB` in `class ThreadDeadlock`,[Trace 2] `void ThreadDeadlock.annotatedWorkerThreadBad()`, locks `this.lockB` in `class ThreadDeadlock`, locks `this` in `class ThreadDeadlock`] +codetoanalyze/java/starvation/ThreadDeadlock.java, ThreadDeadlock.annotatedWorkerThreadBad():void, 42, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void ThreadDeadlock.annotatedWorkerThreadBad()`, locks `this.lockB` in `class ThreadDeadlock`, locks `this` in `class ThreadDeadlock`,[Trace 2] `void ThreadDeadlock.annotatedUiThreadBad()`, locks `this` in `class ThreadDeadlock`, locks `this.lockB` in `class ThreadDeadlock`] +codetoanalyze/java/starvation/ThreadDeadlock.java, ThreadDeadlock.assertOnBackgroundThreadBad():void, 60, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void ThreadDeadlock.assertOnBackgroundThreadBad()`, locks `this.lockC` in `class ThreadDeadlock`, locks `this` in `class ThreadDeadlock`,[Trace 2] `void ThreadDeadlock.assertOnUIThreadBad()`, locks `this` in `class ThreadDeadlock`, locks `this.lockC` in `class ThreadDeadlock`] +codetoanalyze/java/starvation/ThreadDeadlock.java, ThreadDeadlock.assertOnUIThreadBad():void, 52, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void ThreadDeadlock.assertOnUIThreadBad()`, locks `this` in `class ThreadDeadlock`, locks `this.lockC` in `class ThreadDeadlock`,[Trace 2] `void ThreadDeadlock.assertOnBackgroundThreadBad()`, locks `this.lockC` in `class ThreadDeadlock`, locks `this` in `class ThreadDeadlock`] +codetoanalyze/java/starvation/ThreadDeadlock.java, ThreadDeadlock.notAnnotatedBBad():void, 77, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void ThreadDeadlock.notAnnotatedBBad()`, locks `this.lockD` in `class ThreadDeadlock`, locks `this` in `class ThreadDeadlock`,[Trace 2] `void ThreadDeadlock.notAnnotatedBadA()`, locks `this` in `class ThreadDeadlock`, locks `this.lockD` in `class ThreadDeadlock`] +codetoanalyze/java/starvation/ThreadDeadlock.java, ThreadDeadlock.notAnnotatedBadA():void, 71, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void ThreadDeadlock.notAnnotatedBadA()`, locks `this` in `class ThreadDeadlock`, locks `this.lockD` in `class ThreadDeadlock`,[Trace 2] `void ThreadDeadlock.notAnnotatedBBad()`, locks `this.lockD` in `class ThreadDeadlock`, locks `this` in `class ThreadDeadlock`] codetoanalyze/java/starvation/ThreadSensitivity.java, ThreadSensitivity.FP_conditionalIsMainThread_Ok():void, 35, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void ThreadSensitivity.FP_conditionalIsMainThread_Ok()`, locks `this.monitorC` in `class ThreadSensitivity`, locks `this.monitorD` in `class ThreadSensitivity`,[Trace 2] `void ThreadSensitivity.FP_conditionalIsUiThread_Ok()`, locks `this.monitorD` in `class ThreadSensitivity`, locks `this.monitorC` in `class ThreadSensitivity`] codetoanalyze/java/starvation/ThreadSensitivity.java, ThreadSensitivity.FP_conditionalIsUiThread_Ok():void, 44, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void ThreadSensitivity.FP_conditionalIsUiThread_Ok()`, locks `this.monitorD` in `class ThreadSensitivity`, locks `this.monitorC` in `class ThreadSensitivity`,[Trace 2] `void ThreadSensitivity.FP_conditionalIsMainThread_Ok()`, locks `this.monitorC` in `class ThreadSensitivity`, locks `this.monitorD` in `class ThreadSensitivity`] codetoanalyze/java/starvation/ThreadSensitivity.java, ThreadSensitivity.conditionalNegatedIsMainThread_Bad():void, 55, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void ThreadSensitivity.conditionalNegatedIsMainThread_Bad()`, locks `this.monitorE` in `class ThreadSensitivity`, locks `this.monitorF` in `class ThreadSensitivity`,[Trace 2] `void ThreadSensitivity.conditionalNegatedIsMainThread_Bad()`, locks `this.monitorF` in `class ThreadSensitivity`, locks `this.monitorE` in `class ThreadSensitivity`] codetoanalyze/java/starvation/ThreadSensitivity.java, ThreadSensitivity.conditionalNegatedIsMainThread_Bad():void, 60, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void ThreadSensitivity.conditionalNegatedIsMainThread_Bad()`, locks `this.monitorF` in `class ThreadSensitivity`, locks `this.monitorE` in `class ThreadSensitivity`,[Trace 2] `void ThreadSensitivity.conditionalNegatedIsMainThread_Bad()`, locks `this.monitorE` in `class ThreadSensitivity`, locks `this.monitorF` in `class ThreadSensitivity`] codetoanalyze/java/starvation/ThreadSleep.java, ThreadSleep.indirectSleepOnUIThreadBad():void, 24, STARVATION, no_bucket, ERROR, [[Trace 1] `void ThreadSleep.indirectSleepOnUIThreadBad()`, locks `this.lock` in `class ThreadSleep`,[Trace 2] `void ThreadSleep.lockAndSleepOnNonUIThread()`, locks `this.lock` in `class ThreadSleep`,Method call: `void ThreadSleep.sleepOnAnyThreadOk()`,calls `void Thread.sleep(long)`] codetoanalyze/java/starvation/ThreadSleep.java, ThreadSleep.sleepOnUIThreadBad():void, 17, STARVATION, no_bucket, ERROR, [`void ThreadSleep.sleepOnUIThreadBad()`,calls `void Thread.sleep(long)`] -codetoanalyze/java/starvation/UIDeadlock.java, UIDeadlock.notOnUIThreadBad():void, 34, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void UIDeadlock.notOnUIThreadBad()`, locks `this.lockB` in `class UIDeadlock`, locks `this` in `class UIDeadlock`,[Trace 2] `void UIDeadlock.onUIThreadBad()`, locks `this` in `class UIDeadlock`, locks `this.lockB` in `class UIDeadlock`] -codetoanalyze/java/starvation/UIDeadlock.java, UIDeadlock.onUIThreadBad():void, 28, DEADLOCK, no_bucket, ERROR, [[Trace 1] `void UIDeadlock.onUIThreadBad()`, locks `this` in `class UIDeadlock`, locks `this.lockB` in `class UIDeadlock`,[Trace 2] `void UIDeadlock.notOnUIThreadBad()`, locks `this.lockB` in `class UIDeadlock`, locks `this` in `class UIDeadlock`] codetoanalyze/java/starvation/Workers.java, Workers.uiThreadBad():void, 28, STARVATION, no_bucket, ERROR, [`void Workers.uiThreadBad()`,Method call: `void Workers.workerOk()`,Method call: `void Workers.doTransact()`,calls `boolean Binder.transact(int,Parcel,Parcel,int)`]