[clang] [alpha.webkit.UncountedCallArgsChecker] Ignore calls to WTF's container methods (PR #82156)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Feb 18 01:37:18 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-static-analyzer-1
Author: Ryosuke Niwa (rniwa)
<details>
<summary>Changes</summary>
This PR makes the checker ignore / skip calls to methods of Web Template Platform's container types such as HashMap, HashSet, WeakHashSet, WeakHashMap, Vector, etc...
---
Full diff: https://github.com/llvm/llvm-project/pull/82156.diff
2 Files Affected:
- (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp (+32)
- (added) clang/test/Analysis/Checkers/WebKit/call-args-wtf-containers.cpp (+146)
``````````diff
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
index 17a64e1b1b8e04..33e640f4d64654 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
@@ -25,6 +25,11 @@ using namespace ento;
namespace {
+bool stringEndsWith(const std::string& str, const std::string& suffix) {
+ auto index = str.rfind(suffix);
+ return index != std::string::npos && str.size() - suffix.size() == index;
+}
+
class UncountedCallArgsChecker
: public Checker<check::ASTDecl<TranslationUnitDecl>> {
BugType Bug{this,
@@ -165,6 +170,9 @@ class UncountedCallArgsChecker
if (!Callee)
return false;
+ if (isMethodOnWTFContainerType(Callee))
+ return true;
+
auto overloadedOperatorType = Callee->getOverloadedOperator();
if (overloadedOperatorType == OO_EqualEqual ||
overloadedOperatorType == OO_ExclaimEqual ||
@@ -193,6 +201,30 @@ class UncountedCallArgsChecker
return false;
}
+ bool isMethodOnWTFContainerType(const FunctionDecl *Decl) const {
+ if (!isa<CXXMethodDecl>(Decl))
+ return false;
+ auto *ClassDecl = Decl->getParent();
+ if (!ClassDecl || !isa<CXXRecordDecl>(ClassDecl))
+ return false;
+
+ auto *NsDecl = ClassDecl->getParent();
+ if (!NsDecl || !isa<NamespaceDecl>(NsDecl))
+ return false;
+
+ auto methodName = safeGetName(Decl);
+ auto clsName = safeGetName(ClassDecl);
+ auto nsName = safeGetName(NsDecl);
+ // FIXME: These should be implemented via attributes.
+ return nsName == "WTF" &&
+ (methodName == "find" || methodName == "findIf" ||
+ methodName == "reverseFind" || methodName == "reverseFindIf" ||
+ methodName == "get" || methodName == "inlineGet" ||
+ methodName == "contains" || methodName == "containsIf") &&
+ (stringEndsWith(clsName, "Vector") || stringEndsWith(clsName, "Set") ||
+ stringEndsWith(clsName, "Map"));
+ }
+
void reportBug(const Expr *CallArg, const ParmVarDecl *Param) const {
assert(CallArg);
diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-wtf-containers.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-wtf-containers.cpp
new file mode 100644
index 00000000000000..0a63a789856127
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/call-args-wtf-containers.cpp
@@ -0,0 +1,146 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
+
+#include "mock-types.h"
+
+namespace WTF {
+
+ template <typename T>
+ class HashSet {
+ public:
+ template <typename U> T* find(U&) const;
+ template <typename U> bool contains(U&) const;
+ unsigned size() { return m_size; }
+ template <typename U> void add(U&) const;
+ template <typename U> void remove(U&) const;
+
+ private:
+ T* m_table { nullptr };
+ unsigned m_size { 0 };
+ };
+
+ template <typename T, typename S>
+ class HashMap {
+ public:
+ struct Item {
+ T key;
+ S value;
+ };
+
+ template <typename U> Item* find(U&) const;
+ template <typename U> bool contains(U&) const;
+ template <typename U> S* get(U&) const;
+ template <typename U> S* inlineGet(U&) const;
+ template <typename U> void add(U&) const;
+ template <typename U> void remove(U&) const;
+
+ private:
+ Item* m_table { nullptr };
+ };
+
+ template <typename T>
+ class WeakHashSet {
+ public:
+ template <typename U> T* find(U&) const;
+ template <typename U> bool contains(U&) const;
+ template <typename U> void add(U&) const;
+ template <typename U> void remove(U&) const;
+ };
+
+ template <typename T>
+ class Vector {
+ public:
+ unsigned size() { return m_size; }
+ T& at(unsigned i) { return m_buffer[i]; }
+ T& operator[](unsigned i) { return m_buffer[i]; }
+ template <typename U> unsigned find(U&);
+ template <typename U> unsigned reverseFind(U&);
+ template <typename U> bool contains(U&);
+ template <typename MatchFunction> unsigned findIf(const MatchFunction& match)
+ {
+ for (unsigned i = 0; i < m_size; ++i) {
+ if (match(at(i)))
+ return i;
+ }
+ return static_cast<unsigned>(-1);
+ }
+ template <typename MatchFunction> unsigned reverseFindIf(const MatchFunction& match)
+ {
+ for (unsigned i = 0; i < m_size; ++i) {
+ if (match(at(m_size - i)))
+ return i;
+ }
+ return static_cast<unsigned>(-1);
+ }
+ template <typename MatchFunction> bool containsIf(const MatchFunction& match)
+ {
+ for (unsigned i = 0; i < m_size; ++i) {
+ if (match(at(m_size - i)))
+ return true;
+ }
+ return false;
+ }
+ template <typename U> void append(U&) const;
+ template <typename U> void remove(U&) const;
+
+ private:
+ T* m_buffer { nullptr };
+ unsigned m_size { 0 };
+ };
+
+}
+
+using WTF::HashSet;
+using WTF::HashMap;
+using WTF::WeakHashSet;
+using WTF::Vector;
+
+class RefCounted {
+public:
+ void ref() const;
+ void deref() const;
+};
+
+RefCounted* object();
+
+void test() {
+ HashSet<RefPtr<RefCounted>> set;
+ set.find(*object());
+ set.contains(*object());
+ set.add(*object());
+ // expected-warning at -1{{Call argument is uncounted and unsafe}}
+ set.remove(*object());
+ // expected-warning at -1{{Call argument is uncounted and unsafe}}
+
+ HashMap<Ref<RefCounted>, unsigned> map;
+ map.find(*object());
+ map.contains(*object());
+ map.inlineGet(*object());
+ map.add(*object());
+ // expected-warning at -1{{Call argument is uncounted and unsafe}}
+ map.remove(*object());
+ // expected-warning at -1{{Call argument is uncounted and unsafe}}
+
+ WeakHashSet<Ref<RefCounted>> weakSet;
+ weakSet.find(*object());
+ weakSet.contains(*object());
+ weakSet.add(*object());
+ // expected-warning at -1{{Call argument is uncounted and unsafe}}
+ weakSet.remove(*object());
+ // expected-warning at -1{{Call argument is uncounted and unsafe}}
+
+ Vector<Ref<RefCounted>> vector;
+ vector.at(0);
+ vector[0];
+ vector.find(*object());
+ vector.reverseFind(*object());
+ vector.contains(*object());
+ vector.append(*object());
+ // expected-warning at -1{{Call argument is uncounted and unsafe}}
+ vector.remove(*object());
+ // expected-warning at -1{{Call argument is uncounted and unsafe}}
+
+ auto* obj = object();
+ vector.findIf([&](Ref<RefCounted> key) { return key.ptr() == obj; });
+ vector.reverseFindIf([&](Ref<RefCounted> key) { return key.ptr() == obj; });
+ vector.containsIf([&](Ref<RefCounted> key) { return key.ptr() == obj; });
+}
\ No newline at end of file
``````````
</details>
https://github.com/llvm/llvm-project/pull/82156
More information about the cfe-commits
mailing list