You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4.4 KiB

This warning indicates a potential data race in Java. The analyser is called RacerD and this section gives brief but a mostly complete description of its features. See the RacerD page for more in-depth information and examples.

Thread-safety: What is a data race

Here a data race is a pair of accesses to the same member field such that:

  • at least one is a write, and,
  • at least one occurs without any lock synchronization, and,
  • the two accesses occur on threads (if known) which can run in parallel.

Thread-safety: Potential fixes

  • Synchronizing the accesses (using the synchronized keyword, thread-exclusion such as atomic objects, volatile etc).
  • Making an offending method private -- this will exclude it from being checked at the top level, though it will be checked if called by a public method which may itself, e.g., hold a lock when calling it.
  • Putting the two accesses on the same thread, e.g., by using @MainThread or @ThreadConfined.

Thread-safety: Conditions checked before reporting

The class and method are not marked @ThreadSafe(enableChecks = false), and,

  • The method is declared synchronized, or employs (non-transitively) locking, or,
  • The class is not marked @NotThreadSafe, and,
    • The class/method is marked @ThreadSafe, or one of the configured synonyms in .inferconfig, or,
    • A parent class, or an override method are marked with the above annotations.

NB currently RacerD does not take into account @GuardedBy.

Thread-safety: Thread annotations recognized by RacerD

These class and method annotations imply the method is on the main thread: @MainThread, @UiThread

These method annotations imply the method is on the main thread: @OnBind, @OnEvent, @OnMount, @OnUnbind, @OnUnmount

Both classes of annotations work through the inheritance tree (i.e. if a parent class or method is marked with one of these annotations, so is the child class / method override).

In addition to these, RacerD recognizes many lifecycle methods as necessarily running on the main thread, eg Fragment.onCreate etc.

Finally, the thread status of being on the main thread propagates backwards through the call graph (ie if foo calls bar and bar is marked @UiThtread then foo is automatically considered on the main thread too). Calling assertMainThread, assertOnUiThread, checkOnMainThread has the same effect.

NB RacerD currently does not recognize @WorkerThread, @BinderThread or @AnyThread.

Thread-safety: Other annotations and what they do

These annotations can be found at com.facebook.infer.annotation.*.

  • @Functional This is a method annotation indicating the method always returns the same value. When a method foo is annotated @Functional, RacerD will ignore any writes of the return value of foo. For example, in this.x = foo(), the write to this.x is ignored. The reasoning is that if the method returns the same value whenever it's called, any data race on this.x is benign, if that is the only write.

  • @ThreadConfined This is a class/method/field annotation which takes a single parameter which can be UI, ANY or a user chosen string. It indicates to RacerD a thread identifier for the class/method/field. Thus, @ThreadConfined(UI) is equivalent to @UiThread, and @ThreadConfined(ANY) is equivalent to not having the annotation at all, for classes and methods. When this annotation is applied to a field it instructs Infer to assume (without checking) that all accesses to that field are made on the same thread (and can, therefore, not race by definition). The intention is that RacerD uses that to detect exclusion between accesses occurring on the same thread. However, only the UI thread is supported at this time, and any user provided value is considered equal to UI.

  • @VisibleForTesting A method annotation making Infer consider the method as effectively private. This means it will not be checked for races against other non-private methods of the class, but only if called by one.

  • @ReturnsOwnership A method annotation indicating that the method returns a freshly owned object. Accesses to the returned value will not be considered for data races, as the object is in-effect unique and not accessible yet from other threads. The main utility of this annotation is in interfaces, where Infer cannot look up the implementation and decide for itself.