[clang] [Analyzer] Support RefAllowingPartiallyDestroyed and RefPtrAllowingPartiallyDestroyed (PR #82209)
Ryosuke Niwa via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 19 01:37:58 PST 2024
https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/82209
>From d132b98b04d0cfb925f453f99a53f357d95c8e08 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Sun, 18 Feb 2024 21:47:48 -0800
Subject: [PATCH] [Analyzer] Support RefAllowingPartiallyDestroyed and
RefPtrAllowingPartiallyDestroyed
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.
---
.../Checkers/WebKit/PtrTypesSemantics.cpp | 27 +++++------
.../Analysis/Checkers/WebKit/mock-types.h | 3 +-
.../ref-allowing-partially-destroyed.cpp | 45 +++++++++++++++++++
3 files changed, 61 insertions(+), 14 deletions(-)
create mode 100644 clang/test/Analysis/Checkers/WebKit/ref-allowing-partially-destroyed.cpp
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 6f236db0474079..6f768983edb65b 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"
-
- || 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 d08a997aa8c043..e43641c0c61445 100644
--- a/clang/test/Analysis/Checkers/WebKit/mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h
@@ -5,9 +5,10 @@ template <typename T> struct Ref {
T *t;
Ref() : t{} {};
- Ref(T *) {}
+ Ref(T &) {}
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..6a5fbfb67c0c07
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/ref-allowing-partially-destroyed.cpp
@@ -0,0 +1,45 @@
+// 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();
+RefCounted* object3();
+
+void testFunction() {
+ object1()->someFunction();
+ object2()->someFunction();
+}
More information about the cfe-commits
mailing list