tbaeder updated this revision to Diff 533175.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D152504/new/
https://reviews.llvm.org/D152504
Files:
clang/include/clang/Analysis/CFG.h
clang/lib/Analysis/CFG.cpp
clang/lib/Analysis/ThreadSafety.cpp
clang/test/Sema/warn-thread-safety-analysis.c
Index: clang/test/Sema/warn-thread-safety-analysis.c
===================================================================
--- clang/test/Sema/warn-thread-safety-analysis.c
+++ clang/test/Sema/warn-thread-safety-analysis.c
@@ -22,6 +22,7 @@
#define SHARED_LOCKS_REQUIRED(...) \
__attribute__ ((shared_locks_required(__VA_ARGS__)))
#define NO_THREAD_SAFETY_ANALYSIS __attribute__ ((no_thread_safety_analysis))
+#define CLEANUP(A) __attribute__ ((cleanup(A)))
// Define the mutex struct.
// Simplified only for test purpose.
@@ -72,6 +73,11 @@
return *p;
}
+void cleanup_int(int *unused) __attribute__((release_capability(mu1))) {
+ (void)unused;
+ mutex_exclusive_unlock(&mu1);
+}
+
int main(void) {
Foo_fun1(1); // expected-warning{{calling function 'Foo_fun1' requires holding mutex 'mu2'}} \
@@ -127,6 +133,15 @@
// expected-note@-1{{mutex released here}}
mutex_shared_unlock(&mu1); // expected-warning {{releasing mutex 'mu1' that was not held}}
+
+ {
+ mutex_exclusive_lock(&mu1);
+ int CLEANUP(cleanup_int) i;
+
+ Bar_fun1(3);
+ }
+ Bar_fun1(4); // expected-warning {{calling function 'Bar_fun1' requires holding mutex 'mu1' exclusively}}
+
return 0;
}
Index: clang/lib/Analysis/ThreadSafety.cpp
===================================================================
--- clang/lib/Analysis/ThreadSafety.cpp
+++ clang/lib/Analysis/ThreadSafety.cpp
@@ -2427,6 +2427,15 @@
AD.getTriggerStmt()->getEndLoc());
break;
}
+
+ case CFGElement::CleanupFunction: {
+ const CFGCleanupFunction &CF = BI.castAs<CFGCleanupFunction>();
+
+ LocksetBuilder.handleCall(nullptr, CF.getFunctionDecl(), nullptr,
+ CF.getVarDecl()->getLocation());
+ break;
+ }
+
case CFGElement::TemporaryDtor: {
auto TD = BI.castAs<CFGTemporaryDtor>();
Index: clang/lib/Analysis/CFG.cpp
===================================================================
--- clang/lib/Analysis/CFG.cpp
+++ clang/lib/Analysis/CFG.cpp
@@ -866,6 +866,10 @@
B->appendAutomaticObjDtor(VD, S, cfg->getBumpVectorContext());
}
+ void appendCleanupFunction(CFGBlock *B, VarDecl *VD) {
+ B->appendCleanupFunction(VD, cfg->getBumpVectorContext());
+ }
+
void appendLifetimeEnds(CFGBlock *B, VarDecl *VD, Stmt *S) {
B->appendLifetimeEnds(VD, S, cfg->getBumpVectorContext());
}
@@ -1907,7 +1911,8 @@
Decls.push_back(*I);
for (VarDecl *VD : llvm::reverse(Decls)) {
- if (hasTrivialDestructor(VD)) {
+ bool HasCleanupAttr = VD->hasAttr<CleanupAttr>();
+ if (hasTrivialDestructor(VD) && !HasCleanupAttr) {
// If AddScopes is enabled and *I is a first variable in a scope, add a
// ScopeEnd marker in a Block.
if (BuildOpts.AddScopes && DeclsWithEndedScope.count(VD)) {
@@ -1925,7 +1930,8 @@
}
Ty = Context->getBaseElementType(Ty);
- if (Ty->getAsCXXRecordDecl()->isAnyDestructorNoReturn())
+ bool IsCXXRecordType = Ty->getAsCXXRecordDecl() != nullptr;
+ if (IsCXXRecordType && Ty->getAsCXXRecordDecl()->isAnyDestructorNoReturn())
Block = createNoReturnBlock();
else
autoCreateBlock();
@@ -1933,7 +1939,12 @@
// Add ScopeEnd just after automatic obj destructor.
if (BuildOpts.AddScopes && DeclsWithEndedScope.count(VD))
appendScopeEnd(Block, VD, S);
- appendAutomaticObjDtor(Block, VD, S);
+
+ if (HasCleanupAttr)
+ appendCleanupFunction(Block, VD);
+
+ if (IsCXXRecordType)
+ appendAutomaticObjDtor(Block, VD, S);
}
}
@@ -2090,7 +2101,8 @@
return Scope;
if (BuildOpts.AddImplicitDtors) {
- if (!hasTrivialDestructor(VD) || BuildOpts.AddScopes) {
+ if (!hasTrivialDestructor(VD) || VD->hasAttr<CleanupAttr>() ||
+ BuildOpts.AddScopes) {
// Add the variable to scope
Scope = createOrReuseLocalScope(Scope);
Scope->addVar(VD);
@@ -5288,8 +5300,9 @@
case CFGElement::CXXRecordTypedCall:
case CFGElement::ScopeBegin:
case CFGElement::ScopeEnd:
- llvm_unreachable("getDestructorDecl should only be used with "
- "ImplicitDtors");
+ case CFGElement::CleanupFunction:
+ llvm_unreachable("getDestructorDecl should only be used with "
+ "ImplicitDtors");
case CFGElement::AutomaticObjectDtor: {
const VarDecl *var = castAs<CFGAutomaticObjDtor>().getVarDecl();
QualType ty = var->getType();
@@ -5831,6 +5844,12 @@
break;
}
+ case CFGElement::Kind::CleanupFunction: {
+ OS << "CleanupFunction ("
+ << E.castAs<CFGCleanupFunction>().getFunctionDecl()->getName() << ")\n";
+ break;
+ }
+
case CFGElement::Kind::LifetimeEnds:
Helper.handleDecl(E.castAs<CFGLifetimeEnds>().getVarDecl(), OS);
OS << " (Lifetime ends)\n";
Index: clang/include/clang/Analysis/CFG.h
===================================================================
--- clang/include/clang/Analysis/CFG.h
+++ clang/include/clang/Analysis/CFG.h
@@ -14,10 +14,11 @@
#ifndef LLVM_CLANG_ANALYSIS_CFG_H
#define LLVM_CLANG_ANALYSIS_CFG_H
-#include "clang/Analysis/Support/BumpVector.h"
-#include "clang/Analysis/ConstructionContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/Analysis/ConstructionContext.h"
+#include "clang/Analysis/Support/BumpVector.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/GraphTraits.h"
@@ -74,7 +75,8 @@
MemberDtor,
TemporaryDtor,
DTOR_BEGIN = AutomaticObjectDtor,
- DTOR_END = TemporaryDtor
+ DTOR_END = TemporaryDtor,
+ CleanupFunction,
};
protected:
@@ -383,6 +385,32 @@
}
};
+class CFGCleanupFunction final : public CFGElement {
+public:
+ CFGCleanupFunction() = default;
+ CFGCleanupFunction(const VarDecl *VD)
+ : CFGElement(Kind::CleanupFunction, VD) {
+ assert(VD->hasAttr<CleanupAttr>());
+ }
+
+ const VarDecl *getVarDecl() const {
+ return static_cast<VarDecl *>(Data1.getPointer());
+ }
+
+ /// Returns the function to be called when cleaning up the var decl.
+ const FunctionDecl *getFunctionDecl() const {
+ const CleanupAttr *A = getVarDecl()->getAttr<CleanupAttr>();
+ return A->getFunctionDecl();
+ }
+
+private:
+ friend class CFGElement;
+
+ static bool isKind(const CFGElement E) {
+ return E.getKind() == Kind::CleanupFunction;
+ }
+};
+
/// Represents C++ object destructor implicitly generated for automatic object
/// or temporary bound to const reference at the point of leaving its local
/// scope.
@@ -1151,6 +1179,10 @@
Elements.push_back(CFGAutomaticObjDtor(VD, S), C);
}
+ void appendCleanupFunction(const VarDecl *VD, BumpVectorContext &C) {
+ Elements.push_back(CFGCleanupFunction(VD), C);
+ }
+
void appendLifetimeEnds(VarDecl *VD, Stmt *S, BumpVectorContext &C) {
Elements.push_back(CFGLifetimeEnds(VD, S), C);
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits