return;
}
+ if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(Exp)) {
+ if (Analyzer->Handler.issueBetaWarnings()) {
+ checkPtAccess(AE->getLHS(), AK);
+ return;
+ }
+ }
+
if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
if (ME->isArrow())
checkPtAccess(ME->getBase(), AK);
/// \brief Checks pt_guarded_by and pt_guarded_var attributes.
void BuildLockset::checkPtAccess(const Expr *Exp, AccessKind AK) {
- Exp = Exp->IgnoreParenCasts();
+ if (Analyzer->Handler.issueBetaWarnings()) {
+ while (true) {
+ if (const ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) {
+ Exp = PE->getSubExpr();
+ continue;
+ }
+ if (const CastExpr *CE = dyn_cast<CastExpr>(Exp)) {
+ if (CE->getCastKind() == CK_ArrayToPointerDecay) {
+ // If it's an actual array, and not a pointer, then it's elements
+ // are protected by GUARDED_BY, not PT_GUARDED_BY;
+ checkAccess(CE->getSubExpr(), AK);
+ return;
+ }
+ Exp = CE->getSubExpr();
+ continue;
+ }
+ break;
+ }
+ }
+ else
+ Exp = Exp->IgnoreParenCasts();
const ValueDecl *D = getValueDecl(Exp);
if (!D || !D->hasAttrs())
checkAccess(BO->getLHS(), AK_Written);
}
+
/// Whenever we do an LValue to Rvalue cast, we are reading a variable and
/// need to ensure we hold any required mutexes.
/// FIXME: Deal with non-primitive types.
break;
}
case OO_Star:
- case OO_Arrow: {
+ case OO_Arrow:
+ case OO_Subscript: {
if (Analyzer->Handler.issueBetaWarnings()) {
const Expr *Obj = OE->getArg(0);
checkAccess(Obj, AK_Read);
T* get() const { return ptr_; }
T* operator->() const { return ptr_; }
T& operator*() const { return *ptr_; }
+ T& operator[](int i) const { return ptr_[i]; }
private:
T* ptr_;
// This mainly duplicates earlier tests, but just to make sure...
class PtGuardedBySanityTest {
- Mutex mu1;
- Mutex mu2;
- int* a GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
- Cell* c GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
+ Mutex mu1;
+ Mutex mu2;
+ int* a GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
+ Cell* c GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
+ int sa[10] GUARDED_BY(mu1);
+ Cell sc[10] GUARDED_BY(mu1);
void test1() {
mu1.Lock();
if (a == 0) doSomething(); // OK, we don't dereference.
a = 0;
c = 0;
+ if (sa[0] == 42) doSomething();
+ sa[0] = 57;
+ if (sc[0].a == 42) doSomething();
+ sc[0].a = 57;
mu1.Unlock();
}
if ((*c).a == 0) doSomething(); // expected-warning {{reading the value pointed to by 'c' requires locking 'mu2'}}
(*c).a = 0; // expected-warning {{writing the value pointed to by 'c' requires locking 'mu2' exclusively}}
+
+ if (a[0] == 42) doSomething(); // expected-warning {{reading the value pointed to by 'a' requires locking 'mu2'}}
+ a[0] = 57; // expected-warning {{writing the value pointed to by 'a' requires locking 'mu2' exclusively}}
+ if (c[0].a == 42) doSomething(); // expected-warning {{reading the value pointed to by 'c' requires locking 'mu2'}}
+ c[0].a = 57; // expected-warning {{writing the value pointed to by 'c' requires locking 'mu2' exclusively}}
mu1.Unlock();
}
if ((*c).a == 0) doSomething(); // expected-warning {{reading variable 'c' requires locking 'mu1'}}
(*c).a = 0; // expected-warning {{reading variable 'c' requires locking 'mu1'}}
+
+ if (a[0] == 42) doSomething(); // expected-warning {{reading variable 'a' requires locking 'mu1'}}
+ a[0] = 57; // expected-warning {{reading variable 'a' requires locking 'mu1'}}
+ if (c[0].a == 42) doSomething(); // expected-warning {{reading variable 'c' requires locking 'mu1'}}
+ c[0].a = 57; // expected-warning {{reading variable 'c' requires locking 'mu1'}}
mu2.Unlock();
}
- void test4() {
+ void test4() { // Literal arrays
+ if (sa[0] == 42) doSomething(); // expected-warning {{reading variable 'sa' requires locking 'mu1'}}
+ sa[0] = 57; // expected-warning {{writing variable 'sa' requires locking 'mu1' exclusively}}
+ if (sc[0].a == 42) doSomething(); // expected-warning {{reading variable 'sc' requires locking 'mu1'}}
+ sc[0].a = 57; // expected-warning {{writing variable 'sc' requires locking 'mu1' exclusively}}
+
+ if (*sa == 42) doSomething(); // expected-warning {{reading variable 'sa' requires locking 'mu1'}}
+ *sa = 57; // expected-warning {{writing variable 'sa' requires locking 'mu1' exclusively}}
+ if ((*sc).a == 42) doSomething(); // expected-warning {{reading variable 'sc' requires locking 'mu1'}}
+ (*sc).a = 57; // expected-warning {{writing variable 'sc' requires locking 'mu1' exclusively}}
+ if (sc->a == 42) doSomething(); // expected-warning {{reading variable 'sc' requires locking 'mu1'}}
+ sc->a = 57; // expected-warning {{writing variable 'sc' requires locking 'mu1' exclusively}}
+ }
+
+ void test5() {
mu1.ReaderLock(); // OK -- correct use.
mu2.Lock();
if (*a == 0) doSomething();
*sp = 0;
sq->a = 0;
+ if (sp[0] == 0) doSomething();
+ sp[0] = 0;
+
mu2.Unlock();
mu1.Unlock();
}
void test2() {
mu2.Lock();
- sp.get(); // expected-warning {{reading variable 'sp' requires locking 'mu1'}}
- if (*sp == 0) doSomething(); // expected-warning {{reading variable 'sp' requires locking 'mu1'}}
- *sp = 0; // expected-warning {{reading variable 'sp' requires locking 'mu1'}}
- sq->a = 0; // expected-warning {{reading variable 'sq' requires locking 'mu1'}}
+ sp.get(); // expected-warning {{reading variable 'sp' requires locking 'mu1'}}
+ if (*sp == 0) doSomething(); // expected-warning {{reading variable 'sp' requires locking 'mu1'}}
+ *sp = 0; // expected-warning {{reading variable 'sp' requires locking 'mu1'}}
+ sq->a = 0; // expected-warning {{reading variable 'sq' requires locking 'mu1'}}
+
+ if (sp[0] == 0) doSomething(); // expected-warning {{reading variable 'sp' requires locking 'mu1'}}
+ sp[0] = 0; // expected-warning {{reading variable 'sp' requires locking 'mu1'}}
+ if (sq[0].a == 0) doSomething(); // expected-warning {{reading variable 'sq' requires locking 'mu1'}}
+ sq[0].a = 0; // expected-warning {{reading variable 'sq' requires locking 'mu1'}}
mu2.Unlock();
}
mu1.Lock();
sp.get();
- if (*sp == 0) doSomething(); // expected-warning {{reading the value pointed to by 'sp' requires locking 'mu2'}}
- *sp = 0; // expected-warning {{reading the value pointed to by 'sp' requires locking 'mu2'}}
- sq->a = 0; // expected-warning {{reading the value pointed to by 'sq' requires locking 'mu2'}}
+ if (*sp == 0) doSomething(); // expected-warning {{reading the value pointed to by 'sp' requires locking 'mu2'}}
+ *sp = 0; // expected-warning {{reading the value pointed to by 'sp' requires locking 'mu2'}}
+ sq->a = 0; // expected-warning {{reading the value pointed to by 'sq' requires locking 'mu2'}}
+
+ if (sp[0] == 0) doSomething(); // expected-warning {{reading the value pointed to by 'sp' requires locking 'mu2'}}
+ sp[0] = 0; // expected-warning {{reading the value pointed to by 'sp' requires locking 'mu2'}}
+ if (sq[0].a == 0) doSomething(); // expected-warning {{reading the value pointed to by 'sq' requires locking 'mu2'}}
+ sq[0].a = 0; // expected-warning {{reading the value pointed to by 'sq' requires locking 'mu2'}}
mu1.Unlock();
}