PageSourceSearch

https://fbinfer.com/assets/js/20a6a254.b8733e3b.js

js fbinfer.com collected 2026-09-24 17:56:17 UTC 31,414 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunk=globalThis.webpackChunk||[]).push([[4226],{658(e,n,t){t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>o,default:()=>h,frontMatter:()=>r,metadata:()=>a,toc:()=>l});const a=JSON.parse('{"id":"checker-racerd","title":"RacerD","description":"Thread safety analysis.","source":"@site/versioned_docs/version-1.3.0/checker-racerd.md","sourceDirName":".","slug":"/checker-racerd","permalink":"/docs/checker-racerd","draft":false,"unlisted":false,"tags":[],"version":"1.3.0","frontMatter":{"title":"RacerD","description":"Thread safety analysis."},"sidebar":"docs","previous":{"title":"Purity","permalink":"/docs/checker-purity"},"next":{"title":"Resource Leak Lab Exercise","permalink":"/docs/checker-resource-leak-lab"}}');var i=t(4848),s=t(8453);const r={title:"RacerD",description:"Thread safety analysis."},o=void 0,c={},l=[{value:"Background",id:"background",level:2},{value:"Triggering the analysis",id:"triggering-the-analysis",level:2},{value:"Warnings",id:"warnings",level:2},{value:"Unprotected write",id:"unprotected-write",level:3},{value:"Read/Write Race",id:"readwrite-race",level:3},{value:"Interface not thread-safe",id:"interface-not-thread-safe",level:3},{value:"Annotations to help RacerD understand your code",id:"annotations-to-help-racerd-understand-your-code",level:2},{value:"<code>@ThreadConfined</code>",id:"threadconfined",level:3},{value:"<code>@Functional</code>",id:"functional",level:3},{value:"<code>@ReturnsOwnership</code>",id:"returnsownership",level:3},{value:"<code>@VisibleForTesting</code>",id:"visiblefortesting",level:3},{value:"Interprocedural Reasoning",id:"interprocedural-reasoning",level:2},{value:"<a></a> Context and Selected Related Work",id:"-context-and-selected-related-work",level:2},{value:"Limitations",id:"limitations",level:2},{value:"List of Issue Types",id:"list-of-issue-types",level:2}];function d(e){const n={a:"a",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.p,{children:"Thread safety analysis."}),"\n",(0,i.jsxs)(n.p,{children:["Activate with ",(0,i.jsx)(n.code,{children:"--racerd"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"Supported languages:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"C/C++/ObjC: Yes"}),"\n",(0,i.jsx)(n.li,{children:"C#/.Net: Yes"}),"\n",(0,i.jsx)(n.li,{children:"Erlang: No"}),"\n",(0,i.jsx)(n.li,{children:"Hack: No"}),"\n",(0,i.jsx)(n.li,{children:"Java: Yes"}),"\n",(0,i.jsx)(n.li,{children:"Python: No"}),"\n",(0,i.jsx)(n.li,{children:"Rust: No"}),"\n",(0,i.jsx)(n.li,{children:"Swift: No"}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["RacerD finds data races in your C++/Objective C and Java code. This page gives a more in-depth\nexplanation of how the analysis works ",(0,i.jsx)(n.em,{children:"for Java code"}),", but may be less complete than the\n",(0,i.jsx)(n.a,{href:"/docs/all-issue-types#thread_safety_violation",children:"Thread Safety Violation bug description page"}),".\nFor information on C++ and Objective C, see the\n",(0,i.jsx)(n.a,{href:"/docs/all-issue-types#lock_consistency_violation",children:"Lock Consistency violation page"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["To run the analysis, you can use plain ",(0,i.jsx)(n.code,{children:"infer"})," (to run RacerD along with other\nanalyses that are run by default) or ",(0,i.jsx)(n.code,{children:"infer --racerd-only"})," (to run only RacerD)."]}),"\n",(0,i.jsxs)(n.p,{children:["For example, the command ",(0,i.jsx)(n.code,{children:"infer --racerd-only 
1-- javac File.java"})," will run\nRacerD on File.java."]}),"\n",(0,i.jsx)(n.h2,{id:"background",children:"Background"}),"\n",(0,i.jsx)(n.p,{children:"RacerD statically analyzes Java code to detect potential concurrency bugs. This\nanalysis does not attempt to prove the absence of concurrency issues, rather, it\nsearches for a high-confidence class of data races. At the moment RacerD\nconcentrates on race conditions between methods in a class that is itself\nintended to be thread safe. A race condition occurs when there are two\nconcurrent accesses to a class member variable that are not separated by mutual\nexclusion, and at least one of the accesses is a write. Mutual exclusion can be\nensured by synchronization primitives such as locks, or by knowledge that both\naccesses occur on the same thread."}),"\n",(0,i.jsx)(n.h2,{id:"triggering-the-analysis",children:"Triggering the analysis"}),"\n",(0,i.jsxs)(n.p,{children:["RacerD doesn't try to check ",(0,i.jsx)(n.em,{children:"all"})," code for concurrency issues; it only looks at\ncode that it believes can run in a concurrent context. There are two signals\nthat RacerD looks for: (1) Explicitly annotating a class/method with\n",(0,i.jsx)(n.code,{children:"@ThreadSafe"})," and (2) using a lock via the ",(0,i.jsx)(n.code,{children:"synchronized"}
1)," keyword. In both\ncases, RacerD will look for concurrency issues in the code containing the signal\nand all of its dependencies. In particular, it will report races between any\nnon-",(0,i.jsx)(n.code,{children:"private"})," methods of the same class that can perform conflicting accesses.\nAnnotating a class/interface with ",(0,i.jsx)(n.code,{children:"@ThreadSafe"})," also triggers checking for all\nof the subclasses of the class/implementations of the interface."]}),"\n",(0,i.jsx)(n.h2,{id:"warnings",children:"Warnings"}),"\n",(0,i.jsxs)(n.p,{children:["Let's take a look at the different types of concurrency issues that RacerD\nflags. Two of the warning types are data races (",(0,i.jsx)(n.code,{children:"Unprotected write"})," and\n",(0,i.jsx)(n.code,{children:"Read/write race"}),"), and the third warning type encourages adding ",(0,i.jsx)(n.code,{children:"@ThreadSafe"}),"\nannotations to interfaces to trigger additional checking."]}),"\n",(0,i.jsx)(n.h3,{id:"unprotected-write",children:"Unprotected write"}),"\n",(0,i.jsx)(n.p,{children:"RacerD will report an unprotected write when one or more writes can run in\nparallel without synchronization. These come in two flavors: (1) a self-race (a\nwrite-write race that occurs due to a method running in parallel with itself)\nand (2) two conflicting writes to the same location. Here's an example of the\nself-race flavor:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"@ThreadSafe\npublic class Dinner {\n  private int mTemperature;\n\n  public void makeDinner() {\n    boilWater();\n  }\n\n  private void boilWater() {\n    mTemperature = 100; // unprotected write.\n  }\n}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The class ",(0,i.jsx)(n.code,{children:"Dinner"})," will generate the following report on the public method\n",(0,i.jsx)(n.code,{children:"makeDinner()"}),":"]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.code,{children:"There may be a Thread Safety Violation: makeDinner() indirectly writes to mTemperature outside of synchronization."})}),"\n",(0,i.jsxs)(n.p,{children:["This warning can be fixed by synchronizing the access to ",(0,i.jsx)(n.code,{children:"mTemperature"}),", making\n",(0,i.jsx)(n.code,{children:"mTemperature"})," ",(0,i.jsx)(n.code,{children:"volatile"}),", marking ",(0,i.jsx)(n.code,{children:"makeDinner"})," as ",(0,i.jsx)(n.code,{children:"@VisibleForTesting"}),", or\nsuppressing the warning by annotating the ",(0,i.jsx)(n.code,{children:"Dinner"})," class or ",(0,i.jsx)(n.code,{children:"makeDinner"})," method\nwith ",(0,i.jsx)(n.code,{children:"@ThreadSafe(enableChecks = false)"}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"readwrite-race",children:"Read/Write Race"}),"\n",(0,i.jsx)(n.p,{children:"We sometimes need to protect read accesses as well as writes. Consider the\nfollowing class with unsynchronized methods."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"@ThreadSafe\npublic class Account {\n\n  int mBalance = 0;\n\n  public void deposit(int amount) {\n    if (amount > 0) {\n      mBalance += amount;\n    }\n  }\n\n  public int withdraw(int amount){\n    if (amount >= 0 && mBalance - amount >= 0) {\n      mBalance -= amount;\n      return mBalance;\n    } else {\n      return 0;\n    }\n  }\n}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["If you run the ",(0,i.jsx)(n.code,{children:"withdraw()"})," method in parallel with itself or with ",(0,i.jsx)(n.code,{children:"deposit()"}),"\nyou can get unexpected results here. For instance, if the stored balance is 11\nand you run ",(0,i.jsx)(n.code,{children:"withdraw(10)"})," in parallel with itself you can get a negative\nbalance. Furthermore, if you synchronize only the write statement\n",(0,i.jsx)(n.code,{children:"mBalance -= amount"}),", then you can still get this bad result. The reason is that\nthere is a read/write race between the boolean condition\n",(0,i.jsx)(n.code,{children:"mBalance - amount >= 0"})," and the writes. RacerD will duly warn"]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.code,{children:"Read/Write race. Public method int Account.withdraw(int) reads from field Account.mBalance. Potentially races with writes in methods void Account.deposit(int), int Account.withdraw(int)"})}),"\n",(0,i.jsx)(n.p,{children:"on the line with this boolean condition."}),"\n",(0,i.jsxs)(n.p,{children:["A solution to the threading problem here is to make both methods ",(0,i.jsx)(n.code,{children:"synchronized"}),"\nto wrap both read and write accesses, or to use an ",(0,i.jsx)(n.code,{children:"AtomicInteger"})," for\n",(0,i.jsx)(n.code,{children:"mBalance"})," rather than an ordinary ",(0,i.jsx)(n.code,{children:"int"}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"interface-not-thread-safe",children:"Interface not thread-safe"}),"\n",(0,i.jsxs)(n.p,{children:["In the following code, RacerD will report an ",(0,i.jsx)(n.code,{children:"Interface not thread-safe"}
1)," warning\non the call to ",(0,i.jsx)(n.code,{children:"i.bar()"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"interface I {\n  void bar();\n}\n\n@ThreadSafe\nclass C {\n  void foo(I i) {\n    i.bar(); // RacerD warns here\n  }\n}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The way to fix this warning is to add a ",(0,i.jsx)(n.code,{children:"@ThreadSafe"})," annotation to the\ninterface ",(0,i.jsx)(n.code,{children:"I"}),", which will enforce the thread-safety of each of the\nimplementations of ",(0,i.jsx)(n.code,{children:"I"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["You might wonder why it's necessary to annotate ",(0,i.jsx)(n.code,{children:"I"})," -- can't RacerD just look at\nall the implementations of ",(0,i.jsx)(n.code,{children:"i"})," at the call site for ",(0,i.jsx)(n.code,{children:"bar"}),"? Although this is a\nfine idea in principle, it's a bad idea in practice due to a (a) separate\ncompilation and (b) our diff-based deployment model. In the example above, the\ncompiler doesn't have to know about all implementations (or indeed, any\nimplementations) of ",(0,i.jsx)(n.code,{children:"I"})," at the time it compiles this code, so there's no\nguarantee that RacerD will know about or be able to check all implementations of\n",(0,i.jsx)(n.code,{children:"I"}),". That's (a). For (b), say that we check that all implementations of ",(0,i.jsx)(n.code,{children:"I"})," are\nthread-safe at the time this code is written, but we don't add the annotation.\nIf someone else comes along and adds a new implementation of ",(0,i.jsx)(n.code,{children:"I"})," that is not\nthread-safe, RacerD will have no way of knowing that this will cause a potential\nbug in ",(0,i.jsx)(n.code,{children:"foo"}),". But if ",(0,i.jsx)(n.code,{children:"I"})," is annotated, RacerD will enforce that all new\nimplementations of ",(0,i.jsx)(n.code,{children:"I"})," are thread-safe, and ",(0,i.jsx)(n.code,{children:"foo"})," will remain bug-free."]}),"\n",(0,i.jsx)(n.h2,{id:"annotations-to-help-racerd-understand-your-code",children:"Annotations to help RacerD understand your code"}),"\n",(0,i.jsxs)(n.p,{children:["Getting started with RacerD doesn't require any annotations at all -- RacerD\nwill look at your usage of locks and figure out what data is not guarded\nconsistently. But increasing the coverage and signal-to-noise ratio may require\nadding ",(0,i.jsx)(n.code,{children:"@ThreadSafe"})," annotations along with some of the other annotations\ndescribed below. Most of annotations described below can be used via the Maven\nCentral package available\n",(0,i.jsx)(n.a,{href:"https://maven-repository.com/artifact/com.facebook.infer.annotation/infer-annotation",children:"here"}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"threadconfined",children:(0,i.jsx)(n.code,{children:"@ThreadConfined"})}),"\n",(0,i.jsxs)(n.p,{children:["The intuitive idea of thread-safety is that a class is impervious to concurrency\nissues for all c
1oncurrent contexts, even those that have not been written yet\n(it is future-proof). RacerD implements this by naively assuming that any method\ncan potentially be called on any thread. You may determine, however, that an\nobject, method, or field is only ever accessed on a single thread during program\nexecution. Annotating such elements with ",(0,i.jsx)(n.code,{children:"@ThreadConfined"})," informs RacerD of\nthis restriction. Note that a thread-confined method cannot race with itself but\nit can still race with other methods."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"List mCache;\n\n@ThreadConfined(UI)\nvoid prepareCache() {\n  // populate the cache\n  mCache.add(...);\n  // post cache cleanup task to run later\n  mUIExecutor.execute(new Runnable() {\n    @ThreadConfined(UI)\n    public void run() {\n      mCache.clear();\n    }\n  });\n}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["In this example, both ",(0,i.jsx)(n.code,{children:"prepareCache"})," and ",(0,i.jsx)(n.code,{children:"run"})," touch ",(0,i.jsx)(n.code,{children:"mCache"}),". But there's no\npossibility of a race between the two methods because both of them will run\nsequentially on the UI thread. Adding a ",(0,i.jsx)(n.code,{children:"@ThreadConfined(UI)"})," or ",(0,i.jsx)(n.code,{children:"@UiThread"}),"\nannotation to these methods will stop it from warning that there is a race on\n",(0,i.jsx)(n.code,{children:"mCache"}),". We could also choose to add a ",(0,i.jsx)(n.code,{children:"@ThreadConfined"})," annotation to ",(0,i.jsx)(n.code,{children:"mCache"}),"\nitself."]}),"\n",(0,i.jsx)(n.h3,{id:"functional",children:(0,i.jsx)(n.code,{children:"@Functional"})}),"\n",(0,i.jsx)(n.p,{children:"Not all races are bugs; a race can be benign. Consider the following:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"@Functional Boolean askNetworkIfShouldShowFeature();\n\nprivate Boolean mShouldShowFeature;\n\n@ThreadSafe boolean shouldShowFeature() {\n  if (mShouldShowFeature == null) {\n    mShouldShowFeature = askNetworkIfShouldShowFeature();\n  }\n  return mShouldShowFeature;\n}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This code caches the result of an expensive network call that checks whether the\ncurrent user should be shown an experimental feature. This code looks racy, and\nindeed it is: if two threads execute ",(0,i.jsx)(n.code,{children:"shouldShowFeature()"})," at the same time, one\nmay read ",(0,i.jsx)(n.code,{children:"mShouldShowFeature"})," at the same time the other is writing it."]}),"\n",(0,i.jsxs)(n.p,{children:["However, this is actually a ",(0,i.jsx)(n.em,{children:"benign"})," race that the programmer intentionally\nallows for performance reasons. The reason this code is safe is that the\nprogrammer knows that ",(0,i.jsx)(n.code,{children:"askNetworkIfShouldShowFeature()"})," will always return the\nsame value in the same run of the app. Adding synchronization would remove the\nrace, but acquiring/releasing locks and lock contention would potentially slow\ndown every call to ",(0,i.jsx)(n.code,{children:"shouldShowFeature()"}),". The benign race approach makes every\ncall after the first fast without changing the safety of the code."]}),"\n",(0,i.jsxs)(n.p,{children:["RacerD will report a race on this code by default, but adding the\n",(0,i.jsx)(n.code,{children:"@Functional annotation to askNetworkIfShouldShowFeature()"})," informs RacerD that\nthe function is always expected to return the same value. This assumption allows\nRacerD to understand that this particular code is safe, though it will still\n(correctly) warn if ",(0,i.jsx)(n.code,{children:"mShouldShowFeature"})," is read/written elsewhere."]}),"\n",(0,i.jsxs)(n.p,{children:["Be sure not to use the ",(0,i.jsx)(n.code,{children:"@Functional"})," pattern for ",(0,i.jsx)(n.em,{children:"singleton instantiation"}),', as\nit\'s possible the "singleton" can be constructed more than once.']}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"public class MySingleton {\n  private static sInstance;\n\n  // Not @Functional\n  public MySingleton getInstance() {\n    if (sInstance == null) {\n      // Different threads may construct their own instances.\n      sInstance == new MySingleton();\n    }\n    return sInstance;\n  }\n}\n"})}),"\n",(0,i.jsx)(n.h3,{id:"returnsownership",children:(0,i.jsx)(n.code,{children:"@ReturnsOwnership"})}),"\n",(0,i.jsxs)(n.p,{children:["RacerD does not warn on unprotected writes to ",(0,i.jsx)(n.em,{children:"owned"})," objects. An object is\nowned if it has been freshly allocated in the current thread and has not escaped\nto another thread. RacerDf automatically tracks ownership in most cases, but it\nneeds help with ",(0,i.jsx)(n.code,{children:"abstract"})," and ",(0,i.jsx)(n.code,{children:"interface"})," methods that return ownership:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"@ThreadSafe\npublic interface Car {\n  @ReturnsOwnership abstract Car buyCar();\n\n  void carsStuff() {\n    Car myCar = new Car();\n    myCar.wheels = 4; // RacerD won't warn here because it knows myCar is owned\n    Car otherCar = buyCar();\n    otherCar.wheels = 3; // RacerD would normally warn here, but won't because of the `@ReturnsOwnership` annotation\n  }\n}\n"})}),"\n",(0,i.jsx)(n.h3,{id:"visiblefortesting",children:(0,i.jsx)(n.code,{children:"@VisibleForTesting"})}),"\n",(0,i.jsxs)(n.p,{children:["RacerD reports races between any two non",(0,i.jsx)(n.code,{children:"-private"})," methods of a class that may\nrun in a concurrent context. Sometimes, a RacerD report may be false because one\nof the methods cannot actually be called from outside the current class. One fix\nis making the method ",(0,i.jsx)(n.code,{children:"private"})," to enforce this, but this might break unit tests\nthat need to call the method in order to test it. In this case, the\n",(0,i.jsx)(n.code,{children:"@VisibleForTesting"})," annotation will allow RacerD to consider the method as\neffectively ",(0,i.jsx)(n.code,{children:"private"})," and will still allow it to be called from the unit test:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"@VisibleForTesting void setF() {\n  this.f = ...; // RacerD would normally warn here, but @VisibleForTesting will silence the warning\n}
1\n\nsynchronized void setFWithLock() {\n  setF();\n}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Unlike the other annotations shown here, this one lives in\n",(0,i.jsx)(n.a,{href:"https://developer.android.com/reference/android/support/annotation/VisibleForTesting.html",children:"Android"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"interprocedural-reasoning",children:"Interprocedural Reasoning"}),"\n",(0,i.jsx)(n.p,{children:"An important feature of RacerD is that it finds races by analyzing not just one\nfile or class, but by looking at memory accesses that occur after going through\nseveral procedure calls. It handles this even between classes and between files."}),"\n",(0,i.jsx)(n.p,{children:"Here is a very basic example"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"@ThreadSafe\nclass A{\n\n  void m1(B bb) {\n    bb.meth_write();\n  }\n}\n\nclass B{\n Integer x;\n\n void meth_write() {\n   x = 88;\n }\n\n}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Class ",(0,i.jsx)(n.code,{children:"B"})," is not annotated ",(0,i.jsx)(n.code,{children:"@ThreadSafe"})," and does not have any locks, so RacerD\ndoes not directly look for threading issues there. However, method ",(0,i.jsx)(n.code,{children:"m1()"})," in\nclass ",(0,i.jsx)(n.code,{children:"A"})," has a potential self-race, if it is run in parallel with itself and\nthe same argument for each call. RacerD discovers this."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"InterProc.java:17: error: THREAD_SAFETY_VIOLATION\n  Unprotected write. Non-private method `A.m1` indirectly writes to field `&this.B.x` outside of synchronization.\n Reporting because the current class is annotated `@ThreadSafe`, so we assume that this method can run in\n parallel with other non-private methods in the class (incuding itself).\n  15.\n  16.     void m1(B bb) {\n  17. >     bb.meth_write();\n  18.     }\n  19.   }\n"})}),"\n",(0,i.jsxs)(n.p,{children:["RacerD does this sort of reasoning using what is known as a ",(0,i.jsx)(n.em,{children:"compositional\ninteprocedural analysis"}),". There, each method is analyzed independently of its\ncontext to produce a summary of the behaviour of the procedure. In this case the\nsummaries for ",(0,i.jsx)(n.code,{children:"m1()' and"}),"meth()' include information as follows."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"Procedure: void A.m1(B)\nAccesses: { Unprotected({ 1 }) -> { Write to &bb.B.x at void B.meth_write() at line 17 } }\n\nProcedure: void B.meth_write()\nAccesses { Unprotected({ 0 }) -> { Write to &this.B.x at  at line 25 } }\n"})}),"\n",(0,i.jsx)(n.p,{children:"The descriptions here are cryptic and do not include all the information in the\nsummaries, but the main point is that you can use RacerD to look for races in\ncodebases where the mutations done by threads might occur only after a chain of\nprocedure calls."}),"\n",(0,i.jsxs)(n.h2,{id:"-context-and-selected-related-work",children:[(0,i.jsx)("a",{name:"context"})," Context and Selected Related Work"]}),"\n",(0,i.jsx)(n.p,{children:"Reasoning about concurrency divides into bug detection and proving absence of\nbugs. RacerD is on the detection side of reasoning."}),"\n",(0,i.jsxs)(n.p,{children:["The rapid growth in the number of interleavings is problematic for tools that\nattempt exhaustive exploration. With just 150 instructions for two threads, the\nnumber 10^88 of interleavings is more that the estimated number of atoms in the\nknown universe.\n",(0,i.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/Partial_order_reduction",children:"There has been important work which uses various techniques to attempt to reduce the number of interleavings"}),"\nwhile still in principle covering all possibilities, but scale is still a\nchallenge. Note that RacerD is not exhaustive: it has false negatives (missed\nbugs). But in compensation it is fast, and effective (it finds bugs in\npractice)."]}
1),"\n",(0,i.jsxs)(n.p,{children:["Static analysis for concurrency has attracted a lot of attention from\nresearchers, but difficulties with scalability and precision have meant that\nprevious techniques have had little industrial impact. Automatic static race\ndetection itself has seen significant work. The most advanced approaches,\nexemplified by the ",(0,i.jsx)(n.a,{href:"http://www.cis.upenn.edu/~mhnaik/pubs/pldi06.pdf",children:"Chord"}),"\ntool, often use a whole-program analysis paired with a sophisticated alias\nanalysis, two features we have consciously avoided. Generally speaking, the\nleading research tools can be more precise, but RacerD is faster and can operate\nwithout the whole program: we have opted to go for speed in a way that enables\nindustrial deployment on a large, rapidly changing codebase, while trying to use\nas simple techniques as possible to cover many (not all) of the patterns covered\nby slower but precise research tools."]}),"\n",(0,i.jsxs)(n.p,{children:["An industrial static analysis tool from\n",(0,i.jsx)(n.a,{href:"http://homepages.inf.ed.ac.uk/dts/pub/avocs2015.pdf",children:"Contemplate"})," also targets\n@ThreadSafe annotations, but limits the amount of inter-procedural reasoning:\n\u201cThis analysis is interprocedural, but to keep the overall analysis scalable,\nonly calls to private and protected methods on the same class are followed\u201d.\nRacerD does deep, cross-file and cross-class inter-procedural reasoning, and yet\nstill scales; the inter-class capability was one of the first requests from\nFacebook engineers.\n",(0,i.jsx)(n.a,{href:"https://code.facebook.com/posts/1537144479682247/finding-inter-procedural-bugs-at-scale-with-infer-static-analyzer/",children:"A separate blog post looked at 100 recent data race fixes"}),"\nin Infer's deployment in various bug categories, and for data races observed\nthat 53 of them were inter-file (and thus involving multiple classes).\n",(0,i.jsx)(n.a,{href:"#interprocedural-reasoning",children:"See above"})," for an example of RacerD's interprocedural\ncapabilities."]}),"\n",(0,i.jsxs)(n.p,{children:["One reaction to the challenge of developing effective static race detectors has\nbeen to ask the programmer to do more work to help the analyzer. Examples of\nthis approach include the\n",(0,i.jsx)(n.a,{href:"https://clang.llvm.org/docs/ThreadSafetyAnalysis.html",children:"Clang Thread Safety Analyzer"}),",\nthe typing of ",(0,i.jsx)(n.a,{href:"https://doc.rust-lang.org/std/sync/struct.Mutex.html",children:"locks"})," in\nRust, and the use/checking of @GuardedBy annotations in\n",(0,i.jsx)(n.a,{href:"https://homes.cs.washington.edu/~mernst/pubs/locking-semantics-nfm2016.pdf",children:"Java"}),"\nincluding in\n",(0,i.jsx)(n.a,{href:"https://github.com/google/error-prone/blob/master/docs/bugpattern/GuardedBy.md",children:"Google's Error Prone analyzer"}),".\nWhen lock annotations are present they make the analyzer's life easier. It is possible to have a very effective race analysis without decreeing\nthat such annotations must be present. This was essential for our deployment,\nsince ",(0,i.jsx)(n.em,{children:"requiring"})," lock annotations would have been a show stopper for converting\nmany thousands of lines of code to a concurrent context. We believe that this\nfinding should be transportable to new type systems and language designs, as\nwell as to other analyses for existing languages."]}),"\n",(0,i.jsxs)(n.p,{children:["Another reaction to difficulties in static race detection has been to instead\ndevelop dynamic analyses, automatic testing tools which work by running a\nprogram to attempt to find flaws. Google's Thread Sanitizer is a widely used and\nmature tool in this area, which has been used in production to find many bugs in\nC-family languages.\n",(0,i.jsx)(n.a,{href:"http://www.cs.columbia.edu/~junfeng/11fa-e6121/papers/thread-sanitizer.pdf",children:"The Thread Sanitizer authors explicitly call out limitations with static race analyzers"}),"\nas part of their motivation: \u201cIt seems unlikely that static detectors will work\neffectively in our environment: Google\u2019s code is large and complex enough that\nit would be expensive to add the annotations required by a typical static\ndetector\u201d."]}),"\n",(0,i.jsx)(n.p,{children:"We have worked to limit the annotations that RacerD needs, for reasons similar\nthose expressed by the Thread Sanitizer authors. And we have sought to bring the\ncomplementary benefits of static analysis \u2014 possibility of cheaper analysis and\nfast reporting, and ability to analyze code before it is placed in a context to\nrun \u2014 to race detection. But we are interested as well in the future in\nleveraging ideas in the dynamic techniques to improve or add to our analysis for\nrace detection."}),"\n",(0,i.jsx)(n.h2,{id:"limitations",children:"Limitations"}),"\n",(0,i.jsx)(n.p,{children:"There are a number of known limitations to the design of the race detector."}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"It looks for races involving syntactically identical access paths, and misses\nraces due to aliasing"}),"\n",(0,i.jsx)(n.li,{children:"It misses races that arise from a locally declared object escaping its scope"}),"\n",(0,i.jsx)(n.li,{children:"It uses a boolean locks abstraction, and so misses races where tw
1o accesses\nare mistakenly protected by different locks"}),"\n",(0,i.jsx)(n.li,{children:"It assumes a deep ownership model, which misses races where local objects\nrefer to or contain non-owned objects."}),"\n",(0,i.jsx)(n.li,{children:"It avoids reasoning about weak memory and Java's volatile keyword"}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Most of these limitations are consistent with the design goal of reducing false\npositives, even if they lead to false negatives. They also allow technical\ntradeoffs which are different than if we were to favour reduction of false\nnegatives over false positives."}),"\n",(0,i.jsx)(n.p,{children:"A different kind of limitation concerns the bugs searched for: Data races are\nthe most basic form of concurrency error, but there are many types of\nconcurrency issues out there that RacerD does not check for (but might in the\nfuture). Examples include deadlock, atomicity, and check-then-act bugs (shown\nbelow). You must look for these bugs yourself!"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"@ThreadSafe\npublic class SynchronizedList<T> {\n  synchronized boolean isEmpty() { ... }\n  synchronized T add(T item) { ... }\n\n// Not thread safe!!!\npublic class ListUtil<T> {\n  public void addIfEmpty(SynchronizedList<T> list, T item) {\n    if (list.isEmpty()) {\n      // In a race, another thread can add to the list here.\n      list.add(item);\n    }\n  }\n}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Finally, using ",(0,i.jsx)(n.code,{children:"synchronized"})," blindly as a means to fix every unprotected write\nor read is not always safe. Even with RacerD, finding, understanding, and fixing\nconcurrency issues is difficult. If you would like to learn more about best\npractices, ",(0,i.jsx)(n.a,{href:"http://jcip.net/",children:"Java Concurrency in Practice"})," is an excellent\nresource."]}),"\n",(0,i.jsx)(n.h2,{id:"list-of-issue-types",children:"List of Issue Types"}),"\n",(0,i.jsx)(n.p,{children:"The following issue types are reported by this checker:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"/docs/all-issue-types#guardedby_violation",children:"GUARDEDBY_VIOLATION"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"/docs/all-issue-types#interface_not_thread_safe",children:"INTERFACE_NOT_THREAD_SAFE"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"/docs/all-issue-types#lock_consistency_violation",children:"LOCK_CONSISTENCY_VIOLATION"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"/docs/all-issue-types#thread_safety_violation",children:"THREAD_SAFETY_VIOLATION"})}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},8453(e,n,t){t.d(n,{R:()=>r,x:()=>o});var a=t(6540);const i={},s=a.createContext(i);function r(e){const n=a.useContext(s);return a.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),a.createElement(s.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.