[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