[clang] 8b23d68 - [Analyzer] Support RefAllowingPartiallyDestroyed and RefPtrAllowingPartiallyDestroyed (#82209)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 20 23:02:07 PST 2024
Author: Ryosuke Niwa
Date: 2024-02-20T23:02:03-08:00
New Revision: 8b23d68a621f16b6d66e68cb64b99f1221b9df2c
URL: https://github.com/llvm/llvm-project/commit/8b23d68a621f16b6d66e68cb64b99f1221b9df2c
DIFF: https://github.com/llvm/llvm-project/commit/8b23d68a621f16b6d66e68cb64b99f1221b9df2c.diff
LOG: [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.
Added:
clang/test/Analysis/Checkers/WebKit/ref-allowing-partially-destroyed.cpp
Modified:
clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
clang/test/Analysis/Checkers/WebKit/mock-types.h
Removed:
################################################################################
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index a7891d2da07c18..defd83ec8e179c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -103,15 +103,18 @@ std::optional<bool> isRefCountable(const CXXRecordDecl* R)
return hasRef && hasDeref;
}
+bool isRefType(const std::string &Name) {
+ return Name == "Ref" || Name == "RefAllowingPartiallyDestroyed" ||
+ Name == "RefPtr" || Name == "RefPtrAllowingPartiallyDestroyed";
+}
+
bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
assert(F);
- const auto &FunctionName = safeGetName(F);
-
- return FunctionName == "Ref" || FunctionName == "makeRef"
-
- || FunctionName == "RefPtr" || FunctionName == "makeRefPtr"
+ const std::string &FunctionName = safeGetName(F);
- || FunctionName == "UniqueRef" || FunctionName == "makeUniqueRef" ||
+ return isRefType(FunctionName) || FunctionName == "makeRef" ||
+ FunctionName == "makeRefPtr" || FunctionName == "UniqueRef" ||
+ FunctionName == "makeUniqueRef" ||
FunctionName == "makeUniqueRefWithoutFastMallocCheck"
|| FunctionName == "String" || FunctionName == "AtomString" ||
@@ -131,7 +134,7 @@ bool isReturnValueRefCounted(const clang::FunctionDecl *F) {
if (auto *specialT = type->getAs<TemplateSpecializationType>()) {
if (auto *decl = specialT->getTemplateName().getAsTemplateDecl()) {
auto name = decl->getNameAsString();
- return name == "Ref" || name == "RefPtr";
+ return isRefType(name);
}
return false;
}
@@ -172,20 +175,18 @@ std::optional<bool> isGetterOfRefCounted(const CXXMethodDecl* M)
if (isa<CXXMethodDecl>(M)) {
const CXXRecordDecl *calleeMethodsClass = M->getParent();
auto className = safeGetName(calleeMethodsClass);
- auto methodName = safeGetName(M);
+ auto method = safeGetName(M);
- if (((className == "Ref" || className == "RefPtr") &&
- methodName == "get") ||
- (className == "Ref" && methodName == "ptr") ||
+ if ((isRefType(className) && (method == "get" || method == "ptr")) ||
((className == "String" || className == "AtomString" ||
className == "AtomStringImpl" || className == "UniqueString" ||
className == "UniqueStringImpl" || className == "Identifier") &&
- methodName == "impl"))
+ method == "impl"))
return true;
// Ref<T> -> T conversion
// FIXME: Currently allowing any Ref<T> -> whatever cast.
- if (className == "Ref" || className == "RefPtr") {
+ if (isRefType(className)) {
if (auto *maybeRefToRawOperator = dyn_cast<CXXConversionDecl>(M)) {
if (auto *targetConversionType =
maybeRefToRawOperator->getConversionType().getTypePtrOrNull()) {
@@ -202,7 +203,7 @@ bool isRefCounted(const CXXRecordDecl *R) {
if (auto *TmplR = R->getTemplateInstantiationPattern()) {
// FIXME: String/AtomString/UniqueString
const auto &ClassName = safeGetName(TmplR);
- return ClassName == "RefPtr" || ClassName == "Ref";
+ return isRefType(ClassName);
}
return false;
}
diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h
index 82db67bb031dd6..e2b3401d407392 100644
--- a/clang/test/Analysis/Checkers/WebKit/mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h
@@ -16,6 +16,7 @@ template <typename T> struct Ref {
}
T *get() { return t; }
T *ptr() { return t; }
+ T *operator->() { return t; }
operator const T &() const { return *t; }
operator T &() { return *t; }
};
diff --git a/clang/test/Analysis/Checkers/WebKit/ref-allowing-partially-destroyed.cpp b/clang/test/Analysis/Checkers/WebKit/ref-allowing-partially-destroyed.cpp
new file mode 100644
index 00000000000000..6d96c14102a902
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/ref-allowing-partially-destroyed.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
+// expected-no-diagnostics
+
+#include "mock-types.h"
+
+template <typename T> struct RefAllowingPartiallyDestroyed {
+ T *t;
+
+ RefAllowingPartiallyDestroyed() : t{} {};
+ RefAllowingPartiallyDestroyed(T &) {}
+ T *get() { return t; }
+ T *ptr() { return t; }
+ T *operator->() { return t; }
+ operator const T &() const { return *t; }
+ operator T &() { return *t; }
+};
+
+template <typename T> struct RefPtrAllowingPartiallyDestroyed {
+ T *t;
+
+ RefPtrAllowingPartiallyDestroyed() : t(new T) {}
+ RefPtrAllowingPartiallyDestroyed(T *t) : t(t) {}
+ T *get() { return t; }
+ T *operator->() { return t; }
+ const T *operator->() const { return t; }
+ T &operator*() { return *t; }
+ RefPtrAllowingPartiallyDestroyed &operator=(T *) { return *this; }
+ operator bool() { return t; }
+};
+
+class RefCounted {
+public:
+ void ref() const;
+ void deref() const;
+ void someFunction();
+};
+
+RefAllowingPartiallyDestroyed<RefCounted> object1();
+RefPtrAllowingPartiallyDestroyed<RefCounted> object2();
+
+void testFunction() {
+ object1()->someFunction();
+ object2()->someFunction();
+}
More information about the cfe-commits
mailing list