aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/ThreadSafety.cpp
diff options
context:
space:
mode:
authorDeLesley Hutchins <delesley@google.com>2012-06-25 18:33:18 +0000
committerDeLesley Hutchins <delesley@google.com>2012-06-25 18:33:18 +0000
commitf63797c741e646b9482d204c88dee02fb41d7962 (patch)
tree5f4d2df9450a84511f36203364200fc8a75af69f /lib/Analysis/ThreadSafety.cpp
parent8f35d23977bf7e70bab98545db0f687da997f20f (diff)
Thread safety analysis: implement lock_returned attribute.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159152 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/ThreadSafety.cpp')
-rw-r--r--lib/Analysis/ThreadSafety.cpp134
1 files changed, 88 insertions, 46 deletions
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index 075324da5f..2668de1b05 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -84,12 +84,33 @@ namespace {
class MutexID {
SmallVector<NamedDecl*, 2> DeclSeq;
+ /// \brief Encapsulates the lexical context of a function call. The lexical
+ /// context includes the arguments to the call, including the implicit object
+ /// argument. When an attribute containing a mutex expression is attached to
+ /// a method, the expression may refer to formal parameters of the method.
+ /// Actual arguments must be substituted for formal parameters to derive
+ /// the appropriate mutex expression in the lexical context where the function
+ /// is called. PrevCtx holds the context in which the arguments themselves
+ /// should be evaluated; multiple calling contexts can be chained together
+ /// by the lock_returned attribute.
+ struct CallingContext {
+ const NamedDecl* AttrDecl; // The decl to which the attribute is attached.
+ Expr* SelfArg; // Implicit object argument -- e.g. 'this'
+ unsigned NumArgs; // Number of funArgs
+ Expr** FunArgs; // Function arguments
+ CallingContext* PrevCtx; // The previous context; or 0 if none.
+
+ CallingContext(const NamedDecl* D = 0, Expr* S = 0,
+ unsigned N = 0, Expr** A = 0, CallingContext* P = 0)
+ : AttrDecl(D), SelfArg(S), NumArgs(N), FunArgs(A), PrevCtx(P)
+ { }
+ };
+
/// Build a Decl sequence representing the lock from the given expression.
/// Recursive function that terminates on DeclRefExpr.
/// Note: this function merely creates a MutexID; it does not check to
/// ensure that the original expression is a valid mutex expression.
- void buildMutexID(Expr *Exp, const NamedDecl *D, Expr *Parent,
- unsigned NumArgs, Expr **FunArgs) {
+ void buildMutexID(Expr *Exp, CallingContext* CallCtx) {
if (!Exp) {
DeclSeq.clear();
return;
@@ -103,10 +124,11 @@ class MutexID {
cast<FunctionDecl>(PV->getDeclContext())->getCanonicalDecl();
unsigned i = PV->getFunctionScopeIndex();
- if (FunArgs && FD == D->getCanonicalDecl()) {
+ if (CallCtx && CallCtx->FunArgs &&
+ FD == CallCtx->AttrDecl->getCanonicalDecl()) {
// Substitute call arguments for references to function parameters
- assert(i < NumArgs);
- buildMutexID(FunArgs[i], D, 0, 0, 0);
+ assert(i < CallCtx->NumArgs);
+ buildMutexID(CallCtx->FunArgs[i], CallCtx->PrevCtx);
return;
}
// Map the param back to the param of the original function declaration.
@@ -115,54 +137,75 @@ class MutexID {
}
// Not a function parameter -- just store the reference.
DeclSeq.push_back(ND);
- } else if (MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
- NamedDecl *ND = ME->getMemberDecl();
- DeclSeq.push_back(ND);
- buildMutexID(ME->getBase(), D, Parent, NumArgs, FunArgs);
} else if (isa<CXXThisExpr>(Exp)) {
- if (Parent)
- buildMutexID(Parent, D, 0, 0, 0);
+ // Substitute parent for 'this'
+ if (CallCtx && CallCtx->SelfArg)
+ buildMutexID(CallCtx->SelfArg, CallCtx->PrevCtx);
else {
DeclSeq.push_back(0); // Use 0 to represent 'this'.
return; // mutexID is still valid in this case
}
+ } else if (MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
+ NamedDecl *ND = ME->getMemberDecl();
+ DeclSeq.push_back(ND);
+ buildMutexID(ME->getBase(), CallCtx);
} else if (CXXMemberCallExpr *CMCE = dyn_cast<CXXMemberCallExpr>(Exp)) {
+ // When calling a function with a lock_returned attribute, replace
+ // the function call with the expression in lock_returned.
+ if (LockReturnedAttr* At =
+ CMCE->getMethodDecl()->getAttr<LockReturnedAttr>()) {
+ CallingContext LRCallCtx(CMCE->getMethodDecl());
+ LRCallCtx.SelfArg = CMCE->getImplicitObjectArgument();
+ LRCallCtx.NumArgs = CMCE->getNumArgs();
+ LRCallCtx.FunArgs = CMCE->getArgs();
+ LRCallCtx.PrevCtx = CallCtx;
+ buildMutexID(At->getArg(), &LRCallCtx);
+ return;
+ }
DeclSeq.push_back(CMCE->getMethodDecl()->getCanonicalDecl());
- buildMutexID(CMCE->getImplicitObjectArgument(),
- D, Parent, NumArgs, FunArgs);
+ buildMutexID(CMCE->getImplicitObjectArgument(), CallCtx);
unsigned NumCallArgs = CMCE->getNumArgs();
Expr** CallArgs = CMCE->getArgs();
for (unsigned i = 0; i < NumCallArgs; ++i) {
- buildMutexID(CallArgs[i], D, Parent, NumArgs, FunArgs);
+ buildMutexID(CallArgs[i], CallCtx);
}
} else if (CallExpr *CE = dyn_cast<CallExpr>(Exp)) {
- buildMutexID(CE->getCallee(), D, Parent, NumArgs, FunArgs);
+ if (LockReturnedAttr* At =
+ CE->getDirectCallee()->getAttr<LockReturnedAttr>()) {
+ CallingContext LRCallCtx(CE->getDirectCallee());
+ LRCallCtx.NumArgs = CE->getNumArgs();
+ LRCallCtx.FunArgs = CE->getArgs();
+ LRCallCtx.PrevCtx = CallCtx;
+ buildMutexID(At->getArg(), &LRCallCtx);
+ return;
+ }
+ buildMutexID(CE->getCallee(), CallCtx);
unsigned NumCallArgs = CE->getNumArgs();
Expr** CallArgs = CE->getArgs();
for (unsigned i = 0; i < NumCallArgs; ++i) {
- buildMutexID(CallArgs[i], D, Parent, NumArgs, FunArgs);
+ buildMutexID(CallArgs[i], CallCtx);
}
} else if (BinaryOperator *BOE = dyn_cast<BinaryOperator>(Exp)) {
- buildMutexID(BOE->getLHS(), D, Parent, NumArgs, FunArgs);
- buildMutexID(BOE->getRHS(), D, Parent, NumArgs, FunArgs);
+ buildMutexID(BOE->getLHS(), CallCtx);
+ buildMutexID(BOE->getRHS(), CallCtx);
} else if (UnaryOperator *UOE = dyn_cast<UnaryOperator>(Exp)) {
- buildMutexID(UOE->getSubExpr(), D, Parent, NumArgs, FunArgs);
+ buildMutexID(UOE->getSubExpr(), CallCtx);
} else if (ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(Exp)) {
- buildMutexID(ASE->getBase(), D, Parent, NumArgs, FunArgs);
- buildMutexID(ASE->getIdx(), D, Parent, NumArgs, FunArgs);
+ buildMutexID(ASE->getBase(), CallCtx);
+ buildMutexID(ASE->getIdx(), CallCtx);
} else if (AbstractConditionalOperator *CE =
dyn_cast<AbstractConditionalOperator>(Exp)) {
- buildMutexID(CE->getCond(), D, Parent, NumArgs, FunArgs);
- buildMutexID(CE->getTrueExpr(), D, Parent, NumArgs, FunArgs);
- buildMutexID(CE->getFalseExpr(), D, Parent, NumArgs, FunArgs);
+ buildMutexID(CE->getCond(), CallCtx);
+ buildMutexID(CE->getTrueExpr(), CallCtx);
+ buildMutexID(CE->getFalseExpr(), CallCtx);
} else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(Exp)) {
- buildMutexID(CE->getCond(), D, Parent, NumArgs, FunArgs);
- buildMutexID(CE->getLHS(), D, Parent, NumArgs, FunArgs);
- buildMutexID(CE->getRHS(), D, Parent, NumArgs, FunArgs);
+ buildMutexID(CE->getCond(), CallCtx);
+ buildMutexID(CE->getLHS(), CallCtx);
+ buildMutexID(CE->getRHS(), CallCtx);
} else if (CastExpr *CE = dyn_cast<CastExpr>(Exp)) {
- buildMutexID(CE->getSubExpr(), D, Parent, NumArgs, FunArgs);
+ buildMutexID(CE->getSubExpr(), CallCtx);
} else if (ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) {
- buildMutexID(PE->getSubExpr(), D, Parent, NumArgs, FunArgs);
+ buildMutexID(PE->getSubExpr(), CallCtx);
} else if (isa<CharacterLiteral>(Exp) ||
isa<CXXNullPtrLiteralExpr>(Exp) ||
isa<GNUNullExpr>(Exp) ||
@@ -184,43 +227,42 @@ class MutexID {
/// occurs.
/// \param D The declaration to which the lock/unlock attribute is attached.
void buildMutexIDFromExp(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D) {
- Expr *Parent = 0;
- unsigned NumArgs = 0;
- Expr **FunArgs = 0;
+ CallingContext CallCtx(D);
// If we are processing a raw attribute expression, with no substitutions.
if (DeclExp == 0) {
- buildMutexID(MutexExp, D, 0, 0, 0);
+ buildMutexID(MutexExp, 0);
return;
}
- // Examine DeclExp to find Parent and FunArgs, which are used to substitute
+ // Examine DeclExp to find SelfArg and FunArgs, which are used to substitute
// for formal parameters when we call buildMutexID later.
if (MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp)) {
- Parent = ME->getBase();
+ CallCtx.SelfArg = ME->getBase();
} else if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(DeclExp)) {
- Parent = CE->getImplicitObjectArgument();
- NumArgs = CE->getNumArgs();
- FunArgs = CE->getArgs();
+ CallCtx.SelfArg = CE->getImplicitObjectArgument();
+ CallCtx.NumArgs = CE->getNumArgs();
+ CallCtx.FunArgs = CE->getArgs();
} else if (CallExpr *CE = dyn_cast<CallExpr>(DeclExp)) {
- NumArgs = CE->getNumArgs();
- FunArgs = CE->getArgs();
+ CallCtx.NumArgs = CE->getNumArgs();
+ CallCtx.FunArgs = CE->getArgs();
} else if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(DeclExp)) {
- Parent = 0; // FIXME -- get the parent from DeclStmt
- NumArgs = CE->getNumArgs();
- FunArgs = CE->getArgs();
+ CallCtx.SelfArg = 0; // FIXME -- get the parent from DeclStmt
+ CallCtx.NumArgs = CE->getNumArgs();
+ CallCtx.FunArgs = CE->getArgs();
} else if (D && isa<CXXDestructorDecl>(D)) {
// There's no such thing as a "destructor call" in the AST.
- Parent = DeclExp;
+ CallCtx.SelfArg = DeclExp;
}
// If the attribute has no arguments, then assume the argument is "this".
if (MutexExp == 0) {
- buildMutexID(Parent, D, 0, 0, 0);
+ buildMutexID(CallCtx.SelfArg, 0);
return;
}
- buildMutexID(MutexExp, D, Parent, NumArgs, FunArgs);
+ // For most attributes.
+ buildMutexID(MutexExp, &CallCtx);
}
public: