Skip to content

Commit 6d6693e

Browse files
authored
[webkit.RefCntblBaseVirtualDtor] Ignore WTF::RefCounted<T> and its variants missing virtual destructor (#91009)
1 parent b86accc commit 6d6693e

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include "ASTUtils.h"
910
#include "DiagOutputUtils.h"
1011
#include "PtrTypesSemantics.h"
1112
#include "clang/AST/CXXInheritance.h"
@@ -90,6 +91,9 @@ class RefCntblBaseVirtualDtorChecker
9091
const CXXRecordDecl *C = T->getAsCXXRecordDecl();
9192
if (!C)
9293
return false;
94+
if (isRefCountedClass(C))
95+
return false;
96+
9397
bool AnyInconclusiveBase = false;
9498
const auto hasPublicRefInBase =
9599
[&AnyInconclusiveBase](const CXXBaseSpecifier *Base,
@@ -164,6 +168,20 @@ class RefCntblBaseVirtualDtorChecker
164168
return false;
165169
}
166170

171+
static bool isRefCountedClass(const CXXRecordDecl *D) {
172+
if (!D->getTemplateInstantiationPattern())
173+
return false;
174+
auto *NsDecl = D->getParent();
175+
if (!NsDecl || !isa<NamespaceDecl>(NsDecl))
176+
return false;
177+
auto NamespaceName = safeGetName(NsDecl);
178+
auto ClsNameStr = safeGetName(D);
179+
StringRef ClsName = ClsNameStr; // FIXME: Make safeGetName return StringRef.
180+
return NamespaceName == "WTF" &&
181+
(ClsName.ends_with("RefCounted") ||
182+
ClsName == "ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr");
183+
}
184+
167185
void reportBug(const CXXRecordDecl *DerivedClass,
168186
const CXXBaseSpecifier *BaseSpec,
169187
const CXXRecordDecl *ProblematicBaseClass) const {

clang/test/Analysis/Checkers/WebKit/ref-cntbl-base-virtual-dtor-templates.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,63 @@ struct DerivedClassTmpl3 : T { };
2828

2929
typedef DerivedClassTmpl3<RefCntblBase> Foo;
3030
Foo c;
31+
32+
33+
namespace WTF {
34+
35+
class RefCountedBase {
36+
public:
37+
void ref() const { ++count; }
38+
39+
protected:
40+
bool derefBase() const
41+
{
42+
return !--count;
43+
}
44+
45+
private:
46+
mutable unsigned count;
47+
};
48+
49+
template <typename T>
50+
class RefCounted : public RefCountedBase {
51+
public:
52+
void deref() const {
53+
if (derefBase())
54+
delete const_cast<T*>(static_cast<const T*>(this));
55+
}
56+
57+
protected:
58+
RefCounted() { }
59+
};
60+
61+
template <typename T>
62+
class ThreadSafeRefCounted {
63+
public:
64+
void ref() const;
65+
bool deref() const;
66+
};
67+
68+
template <typename T>
69+
class ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr {
70+
public:
71+
void ref() const;
72+
bool deref() const;
73+
};
74+
75+
} // namespace WTF
76+
77+
class DerivedClass4 : public WTF::RefCounted<DerivedClass4> { };
78+
79+
class DerivedClass5 : public DerivedClass4 { };
80+
// expected-warning@-1{{Class 'DerivedClass4' is used as a base of class 'DerivedClass5' but doesn't have virtual destructor}}
81+
82+
class DerivedClass6 : public WTF::ThreadSafeRefCounted<DerivedClass6> { };
83+
84+
class DerivedClass7 : public DerivedClass6 { };
85+
// expected-warning@-1{{Class 'DerivedClass6' is used as a base of class 'DerivedClass7' but doesn't have virtual destructor}}
86+
87+
class DerivedClass8 : public WTF::ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr<DerivedClass8> { };
88+
89+
class DerivedClass9 : public DerivedClass8 { };
90+
// expected-warning@-1{{Class 'DerivedClass8' is used as a base of class 'DerivedClass9' but doesn't have virtual destructor}}

0 commit comments

Comments
 (0)