1 // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s 2 3 #include "mock-types.h" 4 5 namespace WTF { 6 7 constexpr unsigned long notFound = static_cast<unsigned long>(-1); 8 9 class String; 10 class StringImpl; 11 12 class StringView { 13 public: 14 StringView(const String&); 15 private: 16 RefPtr<StringImpl> m_impl; 17 }; 18 19 class StringImpl { 20 public: ref() const21 void ref() const { ++m_refCount; } deref() const22 void deref() const { 23 if (!--m_refCount) 24 delete this; 25 } 26 27 static constexpr unsigned s_flagIs8Bit = 1u << 0; is8Bit() const28 bool is8Bit() const { return m_hashAndFlags & s_flagIs8Bit; } characters8() const29 const char* characters8() const { return m_char8; } characters16() const30 const short* characters16() const { return m_char16; } length() const31 unsigned length() const { return m_length; } 32 Ref<StringImpl> substring(unsigned position, unsigned length) const; 33 34 unsigned long find(char) const; 35 unsigned long find(StringView) const; 36 unsigned long contains(StringView) const; 37 unsigned long findIgnoringASCIICase(StringView) const; 38 39 bool startsWith(StringView) const; 40 bool startsWithIgnoringASCIICase(StringView) const; 41 bool endsWith(StringView) const; 42 bool endsWithIgnoringASCIICase(StringView) const; 43 44 private: 45 mutable unsigned m_refCount { 0 }; 46 unsigned m_length { 0 }; 47 union { 48 const char* m_char8; 49 const short* m_char16; 50 }; 51 unsigned m_hashAndFlags { 0 }; 52 }; 53 54 class String { 55 public: 56 String() = default; String(StringImpl & impl)57 String(StringImpl& impl) : m_impl(&impl) { } String(StringImpl * impl)58 String(StringImpl* impl) : m_impl(impl) { } String(Ref<StringImpl> && impl)59 String(Ref<StringImpl>&& impl) : m_impl(impl.get()) { } impl()60 StringImpl* impl() { return m_impl.get(); } length() const61 unsigned length() const { return m_impl ? m_impl->length() : 0; } characters8() const62 const char* characters8() const { return m_impl ? m_impl->characters8() : nullptr; } characters16() const63 const short* characters16() const { return m_impl ? m_impl->characters16() : nullptr; } 64 is8Bit() const65 bool is8Bit() const { return !m_impl || m_impl->is8Bit(); } 66 find(char character) const67 unsigned long find(char character) const { return m_impl ? m_impl->find(character) : notFound; } find(StringView str) const68 unsigned long find(StringView str) const { return m_impl ? m_impl->find(str) : notFound; } 69 unsigned long findIgnoringASCIICase(StringView) const; 70 contains(char character) const71 bool contains(char character) const { return find(character) != notFound; } 72 bool contains(StringView) const; 73 bool containsIgnoringASCIICase(StringView) const; 74 75 bool startsWith(StringView) const; 76 bool startsWithIgnoringASCIICase(StringView) const; 77 bool endsWith(StringView) const; 78 bool endsWithIgnoringASCIICase(StringView) const; 79 substring(unsigned position,unsigned length) const80 String substring(unsigned position, unsigned length) const 81 { 82 if (!m_impl) 83 return { }; 84 if (!position && length >= m_impl->length()) 85 return *this; 86 return m_impl->substring(position, length); 87 } 88 89 private: 90 RefPtr<StringImpl> m_impl; 91 }; 92 93 template <typename T> 94 class HashSet { 95 public: 96 template <typename U> T* find(U&) const; 97 template <typename U> bool contains(U&) const; size()98 unsigned size() { return m_size; } 99 template <typename U> void add(U&) const; 100 template <typename U> void remove(U&) const; 101 102 private: 103 T* m_table { nullptr }; 104 unsigned m_size { 0 }; 105 }; 106 107 template <typename T, typename S> 108 class HashMap { 109 public: 110 struct Item { 111 T key; 112 S value; 113 }; 114 115 template <typename U> Item* find(U&) const; 116 template <typename U> bool contains(U&) const; 117 template <typename U> S* get(U&) const; 118 template <typename U> S* inlineGet(U&) const; 119 template <typename U> void add(U&) const; 120 template <typename U> void remove(U&) const; 121 122 private: 123 Item* m_table { nullptr }; 124 }; 125 126 template <typename T> 127 class WeakHashSet { 128 public: 129 template <typename U> T* find(U&) const; 130 template <typename U> bool contains(U&) const; 131 template <typename U> void add(U&) const; 132 template <typename U> void remove(U&) const; 133 }; 134 135 template <typename T> 136 class Vector { 137 public: size()138 unsigned size() { return m_size; } at(unsigned i)139 T& at(unsigned i) { return m_buffer[i]; } operator [](unsigned i)140 T& operator[](unsigned i) { return m_buffer[i]; } 141 template <typename U> unsigned find(U&); 142 template <typename U> unsigned reverseFind(U&); 143 template <typename U> bool contains(U&); findIf(const MatchFunction & match)144 template <typename MatchFunction> unsigned findIf(const MatchFunction& match) 145 { 146 for (unsigned i = 0; i < m_size; ++i) { 147 if (match(at(i))) 148 return i; 149 } 150 return static_cast<unsigned>(-1); 151 } reverseFindIf(const MatchFunction & match)152 template <typename MatchFunction> unsigned reverseFindIf(const MatchFunction& match) 153 { 154 for (unsigned i = 0; i < m_size; ++i) { 155 if (match(at(m_size - i))) 156 return i; 157 } 158 return static_cast<unsigned>(-1); 159 } containsIf(const MatchFunction & match)160 template <typename MatchFunction> bool containsIf(const MatchFunction& match) 161 { 162 for (unsigned i = 0; i < m_size; ++i) { 163 if (match(at(m_size - i))) 164 return true; 165 } 166 return false; 167 } 168 template <typename U> void append(U&) const; 169 template <typename U> void remove(U&) const; 170 171 private: 172 T* m_buffer { nullptr }; 173 unsigned m_size { 0 }; 174 }; 175 176 } 177 178 using WTF::StringView; 179 using WTF::StringImpl; 180 using WTF::String; 181 using WTF::HashSet; 182 using WTF::HashMap; 183 using WTF::WeakHashSet; 184 using WTF::Vector; 185 186 class RefCounted { 187 public: 188 void ref() const; 189 void deref() const; 190 }; 191 192 RefCounted* object(); 193 StringImpl* strImpl(); 194 String* str(); 195 StringView strView(); 196 test()197void test() { 198 strImpl()->is8Bit(); 199 strImpl()->characters8(); 200 strImpl()->characters16(); 201 strImpl()->length(); 202 strImpl()->substring(2, 4); 203 strImpl()->find(strView()); 204 strImpl()->contains(strView()); 205 strImpl()->findIgnoringASCIICase(strView()); 206 strImpl()->startsWith(strView()); 207 strImpl()->startsWithIgnoringASCIICase(strView()); 208 strImpl()->endsWith(strView()); 209 strImpl()->endsWithIgnoringASCIICase(strView()); 210 211 str()->is8Bit(); 212 str()->characters8(); 213 str()->characters16(); 214 str()->length(); 215 str()->substring(2, 4); 216 str()->find(strView()); 217 str()->contains(strView()); 218 str()->findIgnoringASCIICase(strView()); 219 str()->startsWith(strView()); 220 str()->startsWithIgnoringASCIICase(strView()); 221 str()->endsWith(strView()); 222 str()->endsWithIgnoringASCIICase(strView()); 223 224 HashSet<RefPtr<RefCounted>> set; 225 set.find(*object()); 226 set.contains(*object()); 227 set.add(*object()); 228 // expected-warning@-1{{Call argument is uncounted and unsafe}} 229 set.remove(*object()); 230 // expected-warning@-1{{Call argument is uncounted and unsafe}} 231 232 HashMap<Ref<RefCounted>, unsigned> map; 233 map.find(*object()); 234 map.contains(*object()); 235 map.inlineGet(*object()); 236 map.add(*object()); 237 // expected-warning@-1{{Call argument is uncounted and unsafe}} 238 map.remove(*object()); 239 // expected-warning@-1{{Call argument is uncounted and unsafe}} 240 241 WeakHashSet<Ref<RefCounted>> weakSet; 242 weakSet.find(*object()); 243 weakSet.contains(*object()); 244 weakSet.add(*object()); 245 // expected-warning@-1{{Call argument is uncounted and unsafe}} 246 weakSet.remove(*object()); 247 // expected-warning@-1{{Call argument is uncounted and unsafe}} 248 249 Vector<Ref<RefCounted>> vector; 250 vector.at(0); 251 vector[0]; 252 vector.find(*object()); 253 vector.reverseFind(*object()); 254 vector.contains(*object()); 255 vector.append(*object()); 256 // expected-warning@-1{{Call argument is uncounted and unsafe}} 257 vector.remove(*object()); 258 // expected-warning@-1{{Call argument is uncounted and unsafe}} 259 260 auto* obj = object(); 261 vector.findIf([&](Ref<RefCounted> key) { return key.ptr() == obj; }); 262 vector.reverseFindIf([&](Ref<RefCounted> key) { return key.ptr() == obj; }); 263 vector.containsIf([&](Ref<RefCounted> key) { return key.ptr() == obj; }); 264 }