diff --git a/infer/tests/codetoanalyze/java/threadsafety/ThreadSafeExample.java b/infer/tests/codetoanalyze/java/threadsafety/ThreadSafeExample.java index 37ea6e150..b0b0122db 100644 --- a/infer/tests/codetoanalyze/java/threadsafety/ThreadSafeExample.java +++ b/infer/tests/codetoanalyze/java/threadsafety/ThreadSafeExample.java @@ -155,44 +155,3 @@ class YesThreadSafeExtendsNotThreadSafeExample extends NotThreadSafeExtendsThrea } } - -class NonThreadSafeClass { - - Object field; - - @ThreadSafe - public void threadSafeMethod() { - this.field = new Object(); // should warn - } - - @ThreadSafe - private void threadSafePrivateMethod() { - this.field = new Object(); // should warn - } - - @ThreadSafe - @VisibleForTesting - public void threadSafeVisibleForTestingMethod() { - this.field = new Object(); // should warn - } - - @ThreadSafe - public void safeMethod() { - } - -} - -class NonThreadSafeSubclass extends NonThreadSafeClass { - - @Override - // overrides method annotated with @ThreadSafe, should warn - public void safeMethod() { - this.field = new Object(); - } - - // won't report this now, but should in the future. if a method annotated with @ThreadSafe - // in class C touches field f, then all other accesses to f in C must also be thread-safe - public void FN_touchesSameFieldAsThreadSafeMethod() { - this.field = new Object(); - } -} diff --git a/infer/tests/codetoanalyze/java/threadsafety/ThreadSafeMethods.java b/infer/tests/codetoanalyze/java/threadsafety/ThreadSafeMethods.java new file mode 100644 index 000000000..c2435dd0b --- /dev/null +++ b/infer/tests/codetoanalyze/java/threadsafety/ThreadSafeMethods.java @@ -0,0 +1,125 @@ +/* + * 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; + + +import com.facebook.infer.annotation.ThreadSafe; +import com.google.common.annotations.VisibleForTesting; + +class ThreadSafeMethods { + + Object field1; + Object field2; + Object field3; + Object field4; + Object field5; + + @ThreadSafe + public void threadSafeMethodWriteBad() { + this.field1 = new Object(); // should warn + } + + @ThreadSafe + public Object threadSafeMethodReadBad() { + return this.field2; + } + + @ThreadSafe + private void threadSafePrivateMethodBad() { + this.field2 = new Object(); // should warn + } + + @ThreadSafe + @VisibleForTesting + public void threadSafeVisibleForTestingMethodBad() { + this.field3 = new Object(); // should warn + } + + @ThreadSafe + public void safeMethodOverride() { + } + + // won't report this now, but should in the future. if a method annotated with @ThreadSafe + // in class C touches field f, then all other accesses to f in C must also be thread-safe + public void FN_writeSameFieldAsThreadSafeMethod1Bad() { + this.field1 = new Object(); + } + + // reads a field that is written in a method marked thread-safe + public Object FN_readSameFieldAsThreadSafeMethod1Bad() { + return this.field1; + } + + public synchronized void safelyWriteSameFieldAsThreadSafeMethod1Ok() { + this.field1 = new Object(); + } + + public synchronized Object safelyReadSameFieldAsThreadSafeMethod1Ok() { + return this.field1; + } + + @ThreadSafe + public synchronized void synchronizedWriteOk() { + this.field4 = new Object(); + } + + // unprotected write to a field that is written safely in a method marked thread-safe + public void FN_writeSameFieldAsThreadSafeMethod2Bad() { + this.field4 = new Object(); + } + + // unprotected read of a field that is written safely in a method marked thread-safe + public Object FN_readSameFieldAsThreadSafeMethod2Bad() { + return this.field4; + } + + @ThreadSafe + public synchronized Object synchronizedReadOk() { + return this.field5; + } + + // unprotected write to a field that is read safely in a method marked thread-safe + public void FN_writeSameFieldAsThreadSafeMethod3Bad() { + this.field5 = new Object(); + } + + // unprotected read of a field that is read safely in a method marked thread-safe + public Object FN_readSameFieldAsThreadSafeMethod3Bad() { + return this.field5; + } + +} + +class ThreadSafeMethodsSubclass extends ThreadSafeMethods { + Object subclassField; + + @Override + // overrides method annotated with @ThreadSafe, should warn + public void safeMethodOverride() { + this.subclassField = new Object(); + } + + public void FN_writeThreadSafeFieldOfSuperclassBad() { + this.field1 = new Object(); + } + + public Object FN_readThreadSafeFieldOfSuperclassBad() { + return this.field1; + } + + public void FN_writeThreadSafeFieldOfOverrideBad() { + this.subclassField = new Object(); + } + + public Object FN_readThreadSafeFieldOfOverrideBad() { + return this.subclassField; + } + +} diff --git a/infer/tests/codetoanalyze/java/threadsafety/issues.exp b/infer/tests/codetoanalyze/java/threadsafety/issues.exp index 3f82798f1..142266457 100644 --- a/infer/tests/codetoanalyze/java/threadsafety/issues.exp +++ b/infer/tests/codetoanalyze/java/threadsafety/issues.exp @@ -74,10 +74,6 @@ codetoanalyze/java/threadsafety/ReadWriteRaces.java, void ReadWriteRaces.readInC codetoanalyze/java/threadsafety/ReadWriteRaces.java, void ReadWriteRaces.unprotectedWrite4Bad(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.ReadWriteRaces.field4] codetoanalyze/java/threadsafety/ThreadSafeExample.java, void ExtendsThreadSafeExample.newmethodBad(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.ExtendsThreadSafeExample.field] codetoanalyze/java/threadsafety/ThreadSafeExample.java, void ExtendsThreadSafeExample.tsOK(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.ExtendsThreadSafeExample.field] -codetoanalyze/java/threadsafety/ThreadSafeExample.java, void NonThreadSafeClass.threadSafeMethod(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.NonThreadSafeClass.field] -codetoanalyze/java/threadsafety/ThreadSafeExample.java, void NonThreadSafeClass.threadSafePrivateMethod(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.NonThreadSafeClass.field] -codetoanalyze/java/threadsafety/ThreadSafeExample.java, void NonThreadSafeClass.threadSafeVisibleForTestingMethod(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.NonThreadSafeClass.field] -codetoanalyze/java/threadsafety/ThreadSafeExample.java, void NonThreadSafeSubclass.safeMethod(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.NonThreadSafeClass.field] codetoanalyze/java/threadsafety/ThreadSafeExample.java, void ThreadSafeExample.callPublicMethodBad(), 1, THREAD_SAFETY_VIOLATION, [call to void ThreadSafeExample.assignInPrivateMethodOk(),access to codetoanalyze.java.checkers.ThreadSafeExample.f] codetoanalyze/java/threadsafety/ThreadSafeExample.java, void ThreadSafeExample.callVisibleForTestingBad(), 1, THREAD_SAFETY_VIOLATION, [call to void ThreadSafeExample.visibleForTestingNotPublicOk(),access to codetoanalyze.java.checkers.ThreadSafeExample.f] codetoanalyze/java/threadsafety/ThreadSafeExample.java, void ThreadSafeExample.deeperTraceBad(), 1, THREAD_SAFETY_VIOLATION, [call to void ThreadSafeExample.callAssignInPrivateMethod(),call to void ThreadSafeExample.assignInPrivateMethodOk(),access to codetoanalyze.java.checkers.ThreadSafeExample.f] @@ -85,3 +81,9 @@ codetoanalyze/java/threadsafety/ThreadSafeExample.java, void ThreadSafeExample.o codetoanalyze/java/threadsafety/ThreadSafeExample.java, void ThreadSafeExample.recursiveBad(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.ThreadSafeExample.f] codetoanalyze/java/threadsafety/ThreadSafeExample.java, void ThreadSafeExample.tsBad(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.ThreadSafeExample.f] codetoanalyze/java/threadsafety/ThreadSafeExample.java, void YesThreadSafeExtendsNotThreadSafeExample.subsubmethodBad(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.YesThreadSafeExtendsNotThreadSafeExample.subsubfield] +codetoanalyze/java/threadsafety/ThreadSafeMethods.java, Object ThreadSafeMethods.synchronizedReadOk(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.ThreadSafeMethods.field5] +codetoanalyze/java/threadsafety/ThreadSafeMethods.java, Object ThreadSafeMethods.threadSafeMethodReadBad(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.ThreadSafeMethods.field2] +codetoanalyze/java/threadsafety/ThreadSafeMethods.java, void ThreadSafeMethods.threadSafeMethodWriteBad(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.ThreadSafeMethods.field1] +codetoanalyze/java/threadsafety/ThreadSafeMethods.java, void ThreadSafeMethods.threadSafePrivateMethodBad(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.ThreadSafeMethods.field2] +codetoanalyze/java/threadsafety/ThreadSafeMethods.java, void ThreadSafeMethods.threadSafeVisibleForTestingMethodBad(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.ThreadSafeMethods.field3] +codetoanalyze/java/threadsafety/ThreadSafeMethods.java, void ThreadSafeMethodsSubclass.safeMethodOverride(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.ThreadSafeMethodsSubclass.subclassField]