Skip to content

Commit fb5a1d6

Browse files
committed
[alpha.webkit.UncountedCallArgsChecker] Ignore calls to WTF's container methods (llvm#82156)
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...
1 parent d103b18 commit fb5a1d6

File tree

2 files changed

+174
-0
lines changed

2 files changed

+174
-0
lines changed

clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@ class UncountedCallArgsChecker
171171
if (!Callee)
172172
return false;
173173

174+
if (isMethodOnWTFContainerType(Callee))
175+
return true;
176+
174177
auto overloadedOperatorType = Callee->getOverloadedOperator();
175178
if (overloadedOperatorType == OO_EqualEqual ||
176179
overloadedOperatorType == OO_ExclaimEqual ||
@@ -199,6 +202,31 @@ class UncountedCallArgsChecker
199202
return false;
200203
}
201204

205+
bool isMethodOnWTFContainerType(const FunctionDecl *Decl) const {
206+
if (!isa<CXXMethodDecl>(Decl))
207+
return false;
208+
auto *ClassDecl = Decl->getParent();
209+
if (!ClassDecl || !isa<CXXRecordDecl>(ClassDecl))
210+
return false;
211+
212+
auto *NsDecl = ClassDecl->getParent();
213+
if (!NsDecl || !isa<NamespaceDecl>(NsDecl))
214+
return false;
215+
216+
auto MethodName = safeGetName(Decl);
217+
auto ClsNameStr = safeGetName(ClassDecl);
218+
StringRef ClsName = ClsNameStr; // FIXME: Make safeGetName return StringRef.
219+
auto NamespaceName = safeGetName(NsDecl);
220+
// FIXME: These should be implemented via attributes.
221+
return NamespaceName == "WTF" &&
222+
(MethodName == "find" || MethodName == "findIf" ||
223+
MethodName == "reverseFind" || MethodName == "reverseFindIf" ||
224+
MethodName == "get" || MethodName == "inlineGet" ||
225+
MethodName == "contains" || MethodName == "containsIf") &&
226+
(ClsName.ends_with("Vector") || ClsName.ends_with("Set") ||
227+
ClsName.ends_with("Map"));
228+
}
229+
202230
void reportBug(const Expr *CallArg, const ParmVarDecl *Param) const {
203231
assert(CallArg);
204232

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
2+
3+
#include "mock-types.h"
4+
5+
namespace WTF {
6+
7+
template <typename T>
8+
class HashSet {
9+
public:
10+
template <typename U> T* find(U&) const;
11+
template <typename U> bool contains(U&) const;
12+
unsigned size() { return m_size; }
13+
template <typename U> void add(U&) const;
14+
template <typename U> void remove(U&) const;
15+
16+
private:
17+
T* m_table { nullptr };
18+
unsigned m_size { 0 };
19+
};
20+
21+
template <typename T, typename S>
22+
class HashMap {
23+
public:
24+
struct Item {
25+
T key;
26+
S value;
27+
};
28+
29+
template <typename U> Item* find(U&) const;
30+
template <typename U> bool contains(U&) const;
31+
template <typename U> S* get(U&) const;
32+
template <typename U> S* inlineGet(U&) const;
33+
template <typename U> void add(U&) const;
34+
template <typename U> void remove(U&) const;
35+
36+
private:
37+
Item* m_table { nullptr };
38+
};
39+
40+
template <typename T>
41+
class WeakHashSet {
42+
public:
43+
template <typename U> T* find(U&) const;
44+
template <typename U> bool contains(U&) const;
45+
template <typename U> void add(U&) const;
46+
template <typename U> void remove(U&) const;
47+
};
48+
49+
template <typename T>
50+
class Vector {
51+
public:
52+
unsigned size() { return m_size; }
53+
T& at(unsigned i) { return m_buffer[i]; }
54+
T& operator[](unsigned i) { return m_buffer[i]; }
55+
template <typename U> unsigned find(U&);
56+
template <typename U> unsigned reverseFind(U&);
57+
template <typename U> bool contains(U&);
58+
template <typename MatchFunction> unsigned findIf(const MatchFunction& match)
59+
{
60+
for (unsigned i = 0; i < m_size; ++i) {
61+
if (match(at(i)))
62+
return i;
63+
}
64+
return static_cast<unsigned>(-1);
65+
}
66+
template <typename MatchFunction> unsigned reverseFindIf(const MatchFunction& match)
67+
{
68+
for (unsigned i = 0; i < m_size; ++i) {
69+
if (match(at(m_size - i)))
70+
return i;
71+
}
72+
return static_cast<unsigned>(-1);
73+
}
74+
template <typename MatchFunction> bool containsIf(const MatchFunction& match)
75+
{
76+
for (unsigned i = 0; i < m_size; ++i) {
77+
if (match(at(m_size - i)))
78+
return true;
79+
}
80+
return false;
81+
}
82+
template <typename U> void append(U&) const;
83+
template <typename U> void remove(U&) const;
84+
85+
private:
86+
T* m_buffer { nullptr };
87+
unsigned m_size { 0 };
88+
};
89+
90+
}
91+
92+
using WTF::HashSet;
93+
using WTF::HashMap;
94+
using WTF::WeakHashSet;
95+
using WTF::Vector;
96+
97+
class RefCounted {
98+
public:
99+
void ref() const;
100+
void deref() const;
101+
};
102+
103+
RefCounted* object();
104+
105+
void test() {
106+
HashSet<RefPtr<RefCounted>> set;
107+
set.find(*object());
108+
set.contains(*object());
109+
set.add(*object());
110+
// expected-warning@-1{{Call argument is uncounted and unsafe}}
111+
set.remove(*object());
112+
// expected-warning@-1{{Call argument is uncounted and unsafe}}
113+
114+
HashMap<Ref<RefCounted>, unsigned> map;
115+
map.find(*object());
116+
map.contains(*object());
117+
map.inlineGet(*object());
118+
map.add(*object());
119+
// expected-warning@-1{{Call argument is uncounted and unsafe}}
120+
map.remove(*object());
121+
// expected-warning@-1{{Call argument is uncounted and unsafe}}
122+
123+
WeakHashSet<Ref<RefCounted>> weakSet;
124+
weakSet.find(*object());
125+
weakSet.contains(*object());
126+
weakSet.add(*object());
127+
// expected-warning@-1{{Call argument is uncounted and unsafe}}
128+
weakSet.remove(*object());
129+
// expected-warning@-1{{Call argument is uncounted and unsafe}}
130+
131+
Vector<Ref<RefCounted>> vector;
132+
vector.at(0);
133+
vector[0];
134+
vector.find(*object());
135+
vector.reverseFind(*object());
136+
vector.contains(*object());
137+
vector.append(*object());
138+
// expected-warning@-1{{Call argument is uncounted and unsafe}}
139+
vector.remove(*object());
140+
// expected-warning@-1{{Call argument is uncounted and unsafe}}
141+
142+
auto* obj = object();
143+
vector.findIf([&](Ref<RefCounted> key) { return key.ptr() == obj; });
144+
vector.reverseFindIf([&](Ref<RefCounted> key) { return key.ptr() == obj; });
145+
vector.containsIf([&](Ref<RefCounted> key) { return key.ptr() == obj; });
146+
}

0 commit comments

Comments
 (0)