https://github.com/rniwa created https://github.com/llvm/llvm-project/pull/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. >From d26f41816f443922569fc713d1cd919fd96ba124 Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa <rn...@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 | 46 +++++++++++++++++++ 3 files changed, 62 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..1b349d48a9f881 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..f9c0f405968231 --- /dev/null +++ b/clang/test/Analysis/Checkers/WebKit/ref-allowing-partially-destroyed.cpp @@ -0,0 +1,46 @@ +// 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(); + RefPtr { object3() }->someFunction(); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits