diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp index 4526fac64735b..b76c0551c77bb 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp @@ -19,6 +19,10 @@ namespace clang { std::pair tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) { while (E) { + if (auto *tempExpr = dyn_cast(E)) { + E = tempExpr->getSubExpr(); + continue; + } if (auto *cast = dyn_cast(E)) { if (StopAtFirstRefCountedObj) { if (auto *ConversionFunc = @@ -62,6 +66,8 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) { E = call->getArg(0); continue; } + if (isReturnValueRefCounted(callee)) + return {E, true}; if (isPtrConversion(callee)) { E = call->getArg(0); diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index d2b6634105800..843c4d5350709 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -118,6 +118,26 @@ bool isCtorOfRefCounted(const clang::FunctionDecl *F) { || FunctionName == "Identifier"; } +bool isReturnValueRefCounted(const clang::FunctionDecl *F) { + assert(F); + QualType type = F->getReturnType(); + while (!type.isNull()) { + if (auto *elaboratedT = type->getAs()) { + type = elaboratedT->desugar(); + continue; + } + if (auto *specialT = type->getAs()) { + if (auto *decl = specialT->getTemplateName().getAsTemplateDecl()) { + auto name = decl->getNameAsString(); + return name == "Ref" || name == "RefPtr"; + } + return false; + } + return false; + } + return false; +} + std::optional isUncounted(const CXXRecordDecl* Class) { // Keep isRefCounted first as it's cheaper. diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h index 45b21cc091844..c2c5b74442ba4 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h @@ -50,6 +50,9 @@ std::optional isUncountedPtr(const clang::Type* T); /// false if not. bool isCtorOfRefCounted(const clang::FunctionDecl *F); +/// \returns true if \p F returns a ref-counted object, false if not. +bool isReturnValueRefCounted(const clang::FunctionDecl *F); + /// \returns true if \p M is getter of a ref-counted class, false if not. std::optional isGetterOfRefCounted(const clang::CXXMethodDecl* Method); diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp new file mode 100644 index 0000000000000..1c4b3df211b1e --- /dev/null +++ b/clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s +// expected-no-diagnostics + +#include "mock-types.h" + +class RefCounted { +public: + void ref(); + void deref(); +}; + +class Object { +public: + void someFunction(RefCounted&); +}; + +RefPtr object(); +RefPtr protectedTargetObject(); + +void testFunction() { + if (RefPtr obj = object()) + obj->someFunction(*protectedTargetObject()); +} diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h index 5f570b8bee8cb..814e094414599 100644 --- a/clang/test/Analysis/Checkers/WebKit/mock-types.h +++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h @@ -20,6 +20,7 @@ template struct RefPtr { T *operator->() { return t; } T &operator*() { return *t; } RefPtr &operator=(T *) { return *this; } + operator bool() { return t; } }; template bool operator==(const RefPtr &, const RefPtr &) {