Summary: A current blind spot is when object construction stores specific executors / runnables to object fields, which are then never mutated and accessed from normal methods. IOW the attributes established in the constructor are necessary to report properly inside a normal method (assuming these attributes are not invalidated by method code). To achieve this, first we retain a subset of the final state attributes in the summary (only those that affect instance variables, in constructor methods). Then, when we analyse a non-constructor method: - we analyse all constructors - remove all attributes from the attribute map whose key is not an expression of the form `this.x. ...` - re-localise all remaining keys so that they appear as rooted in the `this` local variable of the current procedure - join (intersect) all such attribute maps - use the result in place of initial state as far as the attribute map is concerned for the analysis of the current procedure, which can now start. This means we can catch idioms that use side-effectful initialisation for configuring certain object fields like executors or runnables. Reviewed By: jvillard Differential Revision: D18707890 fbshipit-source-id: 42ac6108fmaster
parent
82a9f1ac65
commit
aef34d8384
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* 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.os.Binder;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
class ConstructedAttributes {
|
||||||
|
static Binder binder;
|
||||||
|
|
||||||
|
private static void doTransact() {
|
||||||
|
try {
|
||||||
|
binder.transact(0, null, null, 0);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Executor mUiExecutor;
|
||||||
|
Executor mNonUiExecutor;
|
||||||
|
Handler mUiHandler;
|
||||||
|
Runnable mBadRunnable;
|
||||||
|
Runnable mOkRunnable;
|
||||||
|
|
||||||
|
ConstructedAttributes() {
|
||||||
|
mUiExecutor = Executors.getForegroundExecutor();
|
||||||
|
mNonUiExecutor = Executors.getBackgroundExecutor();
|
||||||
|
mUiHandler = new Handler(Looper.getMainLooper());
|
||||||
|
mBadRunnable =
|
||||||
|
new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
doTransact();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mOkRunnable =
|
||||||
|
new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postBlockingCallToUIExecutorBad() {
|
||||||
|
mUiExecutor.execute(mBadRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postNoopCallToUIExecutorOk() {
|
||||||
|
mUiExecutor.execute(mOkRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postBlockingCallToNonUIExecutorOk() {
|
||||||
|
mNonUiExecutor.execute(mBadRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postBlockingCallToUIHandlerBad() {
|
||||||
|
mUiHandler.post(mBadRunnable);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* 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.os.Binder;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
class ImplicitConstructor {
|
||||||
|
static Binder binder;
|
||||||
|
|
||||||
|
private static void doTransact() {
|
||||||
|
try {
|
||||||
|
binder.transact(0, null, null, 0);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Executor mUiExecutor = Executors.getForegroundExecutor();
|
||||||
|
Executor mNonUiExecutor = Executors.getBackgroundExecutor();
|
||||||
|
Handler mUiHandler = new Handler(Looper.getMainLooper());
|
||||||
|
Runnable mBadRunnable =
|
||||||
|
new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
doTransact();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Runnable mOkRunnable =
|
||||||
|
new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
Runnable mAmbiguous;
|
||||||
|
|
||||||
|
ImplicitConstructor() {
|
||||||
|
mAmbiguous = mBadRunnable;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImplicitConstructor(int data) {
|
||||||
|
mAmbiguous = mOkRunnable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postBlockingCallToUIExecutorBad() {
|
||||||
|
mUiExecutor.execute(mBadRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postNoopCallToUIExecutorOk() {
|
||||||
|
mUiExecutor.execute(mOkRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postBlockingCallToNonUIExecutorOk() {
|
||||||
|
mNonUiExecutor.execute(mBadRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postBlockingCallToUIHandlerBad() {
|
||||||
|
mUiHandler.post(mBadRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postAmbiguousRunnableToUIExecutorOk() {
|
||||||
|
mUiExecutor.execute(mAmbiguous);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue