Skip to content

Commit 8b23d68

Browse files
authored
[Analyzer] Support RefAllowingPartiallyDestroyed and RefPtrAllowingPartiallyDestroyed (#82209)
This PR adds the support for WebKit's RefAllowingPartiallyDestroyed and RefPtrAllowingPartiallyDestroyed, which are smart pointer types which may be used after the destructor had started running.
1 parent ab7dcb0 commit 8b23d68

File tree

3 files changed

+60
-14
lines changed

3 files changed

+60
-14
lines changed

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

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,18 @@ std::optional<bool> isRefCountable(const CXXRecordDecl* R)
103103
return hasRef && hasDeref;
104104
}
105105

106+
bool isRefType(const std::string &Name) {
107+
return Name == "Ref" || Name == "RefAllowingPartiallyDestroyed" ||
108+
Name == "RefPtr" || Name == "RefPtrAllowingPartiallyDestroyed";
109+
}
110+
106111
bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
107112
assert(F);
108-
const auto &FunctionName = safeGetName(F);
109-
110-
return FunctionName == "Ref" || FunctionName == "makeRef"
111-
112-
|| FunctionName == "RefPtr" || FunctionName == "makeRefPtr"
113+
const std::string &FunctionName = safeGetName(F);
113114

114-
|| FunctionName == "UniqueRef" || FunctionName == "makeUniqueRef" ||
115+
return isRefType(FunctionName) || FunctionName == "makeRef" ||
116+
FunctionName == "makeRefPtr" || FunctionName == "UniqueRef" ||
117+
FunctionName == "makeUniqueRef" ||
115118
FunctionName == "makeUniqueRefWithoutFastMallocCheck"
116119

117120
|| FunctionName == "String" || FunctionName == "AtomString" ||
@@ -131,7 +134,7 @@ bool isReturnValueRefCounted(const clang::FunctionDecl *F) {
131134
if (auto *specialT = type->getAs<TemplateSpecializationType>()) {
132135
if (auto *decl = specialT->getTemplateName().getAsTemplateDecl()) {
133136
auto name = decl->getNameAsString();
134-
return name == "Ref" || name == "RefPtr";
137+
return isRefType(name);
135138
}
136139
return false;
137140
}
@@ -172,20 +175,18 @@ std::optional<bool> isGetterOfRefCounted(const CXXMethodDecl* M)
172175
if (isa<CXXMethodDecl>(M)) {
173176
const CXXRecordDecl *calleeMethodsClass = M->getParent();
174177
auto className = safeGetName(calleeMethodsClass);
175-
auto methodName = safeGetName(M);
178+
auto method = safeGetName(M);
176179

177-
if (((className == "Ref" || className == "RefPtr") &&
178-
methodName == "get") ||
179-
(className == "Ref" && methodName == "ptr") ||
180+
if ((isRefType(className) && (method == "get" || method == "ptr")) ||
180181
((className == "String" || className == "AtomString" ||
181182
className == "AtomStringImpl" || className == "UniqueString" ||
182183
className == "UniqueStringImpl" || className == "Identifier") &&
183-
methodName == "impl"))
184+
method == "impl"))
184185
return true;
185186

186187
// Ref<T> -> T conversion
187188
// FIXME: Currently allowing any Ref<T> -> whatever cast.
188-
if (className == "Ref" || className == "RefPtr") {
189+
if (isRefType(className)) {
189190
if (auto *maybeRefToRawOperator = dyn_cast<CXXConversionDecl>(M)) {
190191
if (auto *targetConversionType =
191192
maybeRefToRawOperator->getConversionType().getTypePtrOrNull()) {
@@ -202,7 +203,7 @@ bool isRefCounted(const CXXRecordDecl *R) {
202203
if (auto *TmplR = R->getTemplateInstantiationPattern()) {
203204
// FIXME: String/AtomString/UniqueString
204205
const auto &ClassName = safeGetName(TmplR);
205-
return ClassName == "RefPtr" || ClassName == "Ref";
206+
return isRefType(ClassName);
206207
}
207208
return false;
208209
}

clang/test/Analysis/Checkers/WebKit/mock-types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ template <typename T> struct Ref {
1616
}
1717
T *get() { return t; }
1818
T *ptr() { return t; }
19+
T *operator->() { return t; }
1920
operator const T &() const { return *t; }
2021
operator T &() { return *t; }
2122
};
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
2+
// expected-no-diagnostics
3+
4+
#include "mock-types.h"
5+
6+
template <typename T> struct RefAllowingPartiallyDestroyed {
7+
T *t;
8+
9+
RefAllowingPartiallyDestroyed() : t{} {};
10+
RefAllowingPartiallyDestroyed(T &) {}
11+
T *get() { return t; }
12+
T *ptr() { return t; }
13+
T *operator->() { return t; }
14+
operator const T &() const { return *t; }
15+
operator T &() { return *t; }
16+
};
17+
18+
template <typename T> struct RefPtrAllowingPartiallyDestroyed {
19+
T *t;
20+
21+
RefPtrAllowingPartiallyDestroyed() : t(new T) {}
22+
RefPtrAllowingPartiallyDestroyed(T *t) : t(t) {}
23+
T *get() { return t; }
24+
T *operator->() { return t; }
25+
const T *operator->() const { return t; }
26+
T &operator*() { return *t; }
27+
RefPtrAllowingPartiallyDestroyed &operator=(T *) { return *this; }
28+
operator bool() { return t; }
29+
};
30+
31+
class RefCounted {
32+
public:
33+
void ref() const;
34+
void deref() const;
35+
void someFunction();
36+
};
37+
38+
RefAllowingPartiallyDestroyed<RefCounted> object1();
39+
RefPtrAllowingPartiallyDestroyed<RefCounted> object2();
40+
41+
void testFunction() {
42+
object1()->someFunction();
43+
object2()->someFunction();
44+
}

0 commit comments

Comments
 (0)