https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/82209
>From 1d53adbe50d8afb7c91e8b393c64d6f590256602 Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa <rn...@webkit.org> Date: Sun, 18 Feb 2024 21:47:48 -0800 Subject: [PATCH 1/2] [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 | 1 + .../ref-allowing-partially-destroyed.cpp | 44 +++++++++++++++++++ 3 files changed, 59 insertions(+), 13 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 a7891d2da07c18..c97e7a7a379b96 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 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(); +} >From e395f37d32da3a6a813718e41147c7cac242656e Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa <rn...@webkit.org> Date: Tue, 20 Feb 2024 17:40:50 -0800 Subject: [PATCH 2/2] Address review comment by explicitly declaring std::string instead of using auto. --- .../StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index c97e7a7a379b96..defd83ec8e179c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -103,14 +103,14 @@ 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 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); + const std::string &FunctionName = safeGetName(F); return isRefType(FunctionName) || FunctionName == "makeRef" || FunctionName == "makeRefPtr" || FunctionName == "UniqueRef" || _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits