Summary: Whenever we see a use of a lock, infer that the current method can run in a multithreaded context. But only report when there's a write under a lock that can be read or written without synchronization elsewhere. For now, we only infer this based on the direct usage of a lock; we don't assume a caller runs in a multithreaded context just because its (transitive) callee can. We can work on that trickier case later, and we can work on smarter inference that takes reads under sync into account. But for now, warning on unprotected writes of reads that occur under sync appears to be too noisy. Reviewed By: jberdine Differential Revision: D5918801 fbshipit-source-id: 2450cf2master
parent
2d22b631c3
commit
169df0fe80
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2016 - present Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package codetoanalyze.java.checkers;
|
||||
|
||||
// test that we can infer when code needs to be thread-safe even without annotations
|
||||
public class Inference {
|
||||
|
||||
int mField1;
|
||||
|
||||
synchronized void writeUnderLock1Ok() {
|
||||
mField1 = 1;
|
||||
}
|
||||
|
||||
// should report because there's a write in a method that we think can run on multiple threads
|
||||
int unprotectedRead1Bad() {
|
||||
int ret = mField1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mField2;
|
||||
|
||||
void writeUnderLock2Ok() {
|
||||
synchronized (this) {
|
||||
mField2 = 2;
|
||||
}
|
||||
}
|
||||
|
||||
int unprotectedRead2Bad() {
|
||||
int ret = mField2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TODO: handle these casely separately, since assuming that any method whose (transitive) callee
|
||||
// uses a lock can run on multiple threads may cause a lot of false positives
|
||||
int mField3;
|
||||
|
||||
// empty call that uses a lock
|
||||
synchronized private void useLock() {
|
||||
}
|
||||
|
||||
int useLockInCalleeThenReadBad() {
|
||||
useLock();
|
||||
return mField3;
|
||||
}
|
||||
|
||||
void FN_writeToFieldWrittenInLockUsingMethodBad() {
|
||||
mField3 = 3;
|
||||
}
|
||||
|
||||
int mField4;
|
||||
int mField5;
|
||||
|
||||
synchronized int readInsideSyncCoincidentally() {
|
||||
mField4 = 4; // we will assume this needs to be protected...
|
||||
int ret = mField5; // ...but not this
|
||||
return ret;
|
||||
}
|
||||
|
||||
int read4OutsideSyncBad() {
|
||||
int ret = mField4; // report
|
||||
return ret;
|
||||
}
|
||||
|
||||
void write5OutsideSyncOk() {
|
||||
mField5 = 5; // don't report
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in new issue