diff options
author | DeLesley Hutchins <delesley@google.com> | 2012-06-25 18:33:18 +0000 |
---|---|---|
committer | DeLesley Hutchins <delesley@google.com> | 2012-06-25 18:33:18 +0000 |
commit | f63797c741e646b9482d204c88dee02fb41d7962 (patch) | |
tree | 5f4d2df9450a84511f36203364200fc8a75af69f /lib/Analysis/ThreadSafety.cpp | |
parent | 8f35d23977bf7e70bab98545db0f687da997f20f (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.cpp | 134 |
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: |