Cppcheck
checkstl.h
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2024 Cppcheck team.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 
20 //---------------------------------------------------------------------------
21 #ifndef checkstlH
22 #define checkstlH
23 //---------------------------------------------------------------------------
24 
25 #include "check.h"
26 #include "config.h"
27 #include "errortypes.h"
28 #include "tokenize.h"
29 #include "vfvalue.h"
30 
31 #include <string>
32 
33 class Scope;
34 class Settings;
35 class Token;
36 class Variable;
37 class ErrorLogger;
38 
39 
40 /// @addtogroup Checks
41 /// @{
42 
43 
44 /** @brief %Check STL usage (invalidation of iterators, mismatching containers, etc) */
45 class CPPCHECKLIB CheckStl : public Check {
46 public:
47  /** This constructor is used when registering the CheckClass */
48  CheckStl() : Check(myName()) {}
49 
50 private:
51  /** This constructor is used when running checks. */
52  CheckStl(const Tokenizer* tokenizer, const Settings* settings, ErrorLogger* errorLogger)
53  : Check(myName(), tokenizer, settings, errorLogger) {}
54 
55  /** run checks, the token list is not simplified */
56  void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override {
57  if (!tokenizer.isCPP()) {
58  return;
59  }
60 
61  CheckStl checkStl(&tokenizer, &tokenizer.getSettings(), errorLogger);
62  checkStl.erase();
63  checkStl.if_find();
64  checkStl.checkFindInsert();
65  checkStl.iterators();
66  checkStl.missingComparison();
67  checkStl.outOfBounds();
68  checkStl.outOfBoundsIndexExpression();
69  checkStl.redundantCondition();
70  checkStl.string_c_str();
71  checkStl.uselessCalls();
72  checkStl.useStlAlgorithm();
73 
74  checkStl.stlOutOfBounds();
75  checkStl.negativeIndex();
76 
77  checkStl.invalidContainer();
78  checkStl.mismatchingContainers();
80  checkStl.knownEmptyContainer();
81  checkStl.eraseIteratorOutOfBounds();
82 
83  checkStl.stlBoundaries();
86  checkStl.checkMutexes();
87 
88  // Style check
89  checkStl.size();
90  }
91 
92  /** Accessing container out of bounds using ValueFlow */
93  void outOfBounds();
94 
95  /** Accessing container out of bounds, following index expression */
96  void outOfBoundsIndexExpression();
97 
98  /**
99  * Finds errors like this:
100  * for (unsigned ii = 0; ii <= foo.size(); ++ii)
101  */
102  void stlOutOfBounds();
103 
104  /**
105  * negative index for array like containers
106  */
107  void negativeIndex();
108 
109  /**
110  * Finds errors like this:
111  * for (it = foo.begin(); it != bar.end(); ++it)
112  */
113  void iterators();
114 
115  void invalidContainer();
116 
117  bool checkIteratorPair(const Token* tok1, const Token* tok2);
118 
119  /**
120  * Mismatching containers:
121  * std::find(foo.begin(), bar.end(), x)
122  */
123  void mismatchingContainers();
124 
125  void mismatchingContainerIterator();
126 
127  /**
128  * Dangerous usage of erase. The iterator is invalidated by erase so
129  * it is bad to dereference it after the erase.
130  */
131  void erase();
132  void eraseCheckLoopVar(const Scope& scope, const Variable* var);
133 
134  /**
135  * bad condition.. "it < alist.end()"
136  */
137  void stlBoundaries();
138 
139  /** if (a.find(x)) - possibly incorrect condition */
140  void if_find();
141 
142  void checkFindInsert();
143 
144  /**
145  * Suggest using empty() instead of checking size() against zero for containers.
146  * Item 4 from Scott Meyers book "Effective STL".
147  */
148  void size();
149 
150  /**
151  * Check for redundant condition 'if (ints.find(1) != ints.end()) ints.remove(123);'
152  * */
153  void redundantCondition();
154 
155  /**
156  * @brief Missing inner comparison, when incrementing iterator inside loop
157  * Dangers:
158  * - may increment iterator beyond end
159  * - may unintentionally skip elements in list/set etc
160  */
161  void missingComparison();
162 
163  /** Check for common mistakes when using the function string::c_str() */
164  void string_c_str();
165 
166  /** @brief %Check calls that using them is useless */
167  void uselessCalls();
168 
169  /** @brief %Check for dereferencing an iterator that is invalid */
170  void checkDereferenceInvalidIterator();
171  void checkDereferenceInvalidIterator2();
172 
173  /**
174  * Dereferencing an erased iterator
175  * @param erased token where the erase occurs
176  * @param deref token where the dereference occurs
177  * @param itername iterator name
178  * @param inconclusive inconclusive flag
179  */
180  void dereferenceErasedError(const Token* erased, const Token* deref, const std::string& itername, bool inconclusive);
181 
182  /** @brief Look for loops that can replaced with std algorithms */
183  void useStlAlgorithm();
184 
185  void knownEmptyContainer();
186 
187  void eraseIteratorOutOfBounds();
188 
189  void checkMutexes();
190 
191  bool isContainerSize(const Token *containerToken, const Token *expr) const;
192  bool isContainerSizeGE(const Token * containerToken, const Token *expr) const;
193 
194  void missingComparisonError(const Token* incrementToken1, const Token* incrementToken2);
195  void string_c_strThrowError(const Token* tok);
196  void string_c_strError(const Token* tok);
197  void string_c_strReturn(const Token* tok);
198  void string_c_strParam(const Token* tok, nonneg int number, const std::string& argtype = "std::string");
199  void string_c_strConstructor(const Token* tok, const std::string& argtype = "std::string");
200  void string_c_strAssignment(const Token* tok, const std::string& argtype = "std::string");
201  void string_c_strConcat(const Token* tok);
202  void string_c_strStream(const Token* tok);
203 
204  void outOfBoundsError(const Token *tok, const std::string &containerName, const ValueFlow::Value *containerSize, const std::string &index, const ValueFlow::Value *indexValue);
205  void outOfBoundsIndexExpressionError(const Token *tok, const Token *index);
206  void stlOutOfBoundsError(const Token* tok, const std::string& num, const std::string& var, bool at);
207  void negativeIndexError(const Token* tok, const ValueFlow::Value& index);
208  void invalidIteratorError(const Token* tok, const std::string& iteratorName);
209  void iteratorsError(const Token* tok, const std::string& containerName1, const std::string& containerName2);
210  void iteratorsError(const Token* tok, const Token* containerTok, const std::string& containerName1, const std::string& containerName2);
211  void iteratorsError(const Token* tok, const Token* containerTok, const std::string& containerName);
212  void mismatchingContainerIteratorError(const Token* containerTok, const Token* iterTok, const Token* containerTok2);
213  void mismatchingContainersError(const Token* tok1, const Token* tok2);
214  void mismatchingContainerExpressionError(const Token *tok1, const Token *tok2);
215  void sameIteratorExpressionError(const Token *tok);
216  void stlBoundariesError(const Token* tok);
217  void if_findError(const Token* tok, bool str);
218  void checkFindInsertError(const Token *tok);
219  void sizeError(const Token* tok);
220  void redundantIfRemoveError(const Token* tok);
221  void invalidContainerLoopError(const Token* tok, const Token* loopTok, ErrorPath errorPath);
222  void invalidContainerError(const Token *tok, const Token * contTok, const ValueFlow::Value *val, ErrorPath errorPath);
223  void invalidContainerReferenceError(const Token* tok, const Token* contTok, ErrorPath errorPath);
224 
225  void uselessCallsReturnValueError(const Token* tok, const std::string& varname, const std::string& function);
226  void uselessCallsSwapError(const Token* tok, const std::string& varname);
227  enum class SubstrErrorType { EMPTY, COPY, PREFIX, PREFIX_CONCAT };
228  void uselessCallsSubstrError(const Token* tok, SubstrErrorType type);
229  void uselessCallsEmptyError(const Token* tok);
230  void uselessCallsRemoveError(const Token* tok, const std::string& function);
231  void uselessCallsConstructorError(const Token* tok);
232 
233  void dereferenceInvalidIteratorError(const Token* deref, const std::string& iterName);
234  void dereferenceInvalidIteratorError(const Token* tok, const ValueFlow::Value *value, bool inconclusive);
235 
236  void useStlAlgorithmError(const Token *tok, const std::string &algoName);
237 
238  void knownEmptyContainerError(const Token *tok, const std::string& algo);
239 
240  void eraseIteratorOutOfBoundsError(const Token* ftok, const Token* itertok, const ValueFlow::Value* val = nullptr);
241 
242  void globalLockGuardError(const Token *tok);
243  void localMutexError(const Token *tok);
244 
245  void getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const override {
246  CheckStl c(nullptr, settings, errorLogger);
247  c.outOfBoundsError(nullptr, "container", nullptr, "x", nullptr);
248  c.invalidIteratorError(nullptr, "iterator");
249  c.iteratorsError(nullptr, "container1", "container2");
250  c.iteratorsError(nullptr, nullptr, "container0", "container1");
251  c.iteratorsError(nullptr, nullptr, "container");
252  c.invalidContainerLoopError(nullptr, nullptr, ErrorPath{});
253  c.invalidContainerError(nullptr, nullptr, nullptr, ErrorPath{});
254  c.mismatchingContainerIteratorError(nullptr, nullptr, nullptr);
255  c.mismatchingContainersError(nullptr, nullptr);
256  c.mismatchingContainerExpressionError(nullptr, nullptr);
257  c.sameIteratorExpressionError(nullptr);
258  c.dereferenceErasedError(nullptr, nullptr, "iter", false);
259  c.stlOutOfBoundsError(nullptr, "i", "foo", false);
260  c.negativeIndexError(nullptr, ValueFlow::Value(-1));
261  c.stlBoundariesError(nullptr);
262  c.if_findError(nullptr, false);
263  c.if_findError(nullptr, true);
264  c.checkFindInsertError(nullptr);
265  c.string_c_strError(nullptr);
266  c.string_c_strReturn(nullptr);
267  c.string_c_strParam(nullptr, 0);
268  c.string_c_strThrowError(nullptr);
269  c.sizeError(nullptr);
270  c.missingComparisonError(nullptr, nullptr);
271  c.redundantIfRemoveError(nullptr);
272  c.uselessCallsReturnValueError(nullptr, "str", "find");
273  c.uselessCallsSwapError(nullptr, "str");
274  c.uselessCallsSubstrError(nullptr, SubstrErrorType::COPY);
275  c.uselessCallsEmptyError(nullptr);
276  c.uselessCallsRemoveError(nullptr, "remove");
277  c.dereferenceInvalidIteratorError(nullptr, "i");
278  c.eraseIteratorOutOfBoundsError(nullptr, nullptr);
279  c.useStlAlgorithmError(nullptr, emptyString);
281  c.globalLockGuardError(nullptr);
282  c.localMutexError(nullptr);
283  }
284 
285  static std::string myName() {
286  return "STL usage";
287  }
288 
289  std::string classInfo() const override {
290  return "Check for invalid usage of STL:\n"
291  "- out of bounds errors\n"
292  "- misuse of iterators when iterating through a container\n"
293  "- mismatching containers in calls\n"
294  "- same iterators in calls\n"
295  "- dereferencing an erased iterator\n"
296  "- for vectors: using iterator/pointer after push_back has been used\n"
297  "- optimisation: use empty() instead of size() to guarantee fast code\n"
298  "- suspicious condition when using find\n"
299  "- unnecessary searching in associative containers\n"
300  "- redundant condition\n"
301  "- common mistakes when using string::c_str()\n"
302  "- useless calls of string and STL functions\n"
303  "- dereferencing an invalid iterator\n"
304  "- erasing an iterator that is out of bounds\n"
305  "- reading from empty STL container\n"
306  "- iterating over an empty STL container\n"
307  "- consider using an STL algorithm instead of raw loop\n"
308  "- incorrect locking with mutex\n";
309  }
310 };
311 /// @}
312 //---------------------------------------------------------------------------
313 #endif // checkstlH
Check STL usage (invalidation of iterators, mismatching containers, etc)
Definition: checkstl.h:45
CheckStl()
This constructor is used when registering the CheckClass.
Definition: checkstl.h:48
void outOfBoundsIndexExpression()
Accessing container out of bounds, following index expression.
Definition: checkstl.cpp:320
void missingComparison()
Missing inner comparison, when incrementing iterator inside loop Dangers:
Definition: checkstl.cpp:1860
void erase()
Dangerous usage of erase.
Definition: checkstl.cpp:1379
void missingComparisonError(const Token *incrementToken1, const Token *incrementToken2)
Definition: checkstl.cpp:1924
void sizeError(const Token *tok)
Definition: checkstl.cpp:1807
void uselessCalls()
Check calls that using them is useless
Definition: checkstl.cpp:2226
void checkDereferenceInvalidIterator2()
Definition: checkstl.cpp:2416
void stlBoundariesError(const Token *tok)
Definition: checkstl.cpp:1469
void uselessCallsSubstrError(const Token *tok, SubstrErrorType type)
Definition: checkstl.cpp:2310
void invalidContainerError(const Token *tok, const Token *contTok, const ValueFlow::Value *val, ErrorPath errorPath)
Definition: checkstl.cpp:1229
void mismatchingContainerIteratorError(const Token *containerTok, const Token *iterTok, const Token *containerTok2)
Definition: checkstl.cpp:649
void uselessCallsSwapError(const Token *tok, const std::string &varname)
Definition: checkstl.cpp:2300
std::string classInfo() const override
get information about this class, used to generate documentation
Definition: checkstl.h:289
void knownEmptyContainerError(const Token *tok, const std::string &algo)
Definition: checkstl.cpp:3075
void size()
Suggest using empty() instead of checking size() against zero for containers.
Definition: checkstl.cpp:1758
void mismatchingContainersError(const Token *tok1, const Token *tok2)
Definition: checkstl.cpp:663
void eraseIteratorOutOfBoundsError(const Token *ftok, const Token *itertok, const ValueFlow::Value *val=nullptr)
Definition: checkstl.cpp:3149
void uselessCallsRemoveError(const Token *tok, const std::string &function)
Definition: checkstl.cpp:2341
void uselessCallsReturnValueError(const Token *tok, const std::string &varname, const std::string &function)
Definition: checkstl.cpp:2287
void sameIteratorExpressionError(const Token *tok)
Definition: checkstl.cpp:684
void stlOutOfBounds()
Finds errors like this: for (unsigned ii = 0; ii <= foo.size(); ++ii)
Definition: checkstl.cpp:1247
void string_c_strParam(const Token *tok, nonneg int number, const std::string &argtype="std::string")
Definition: checkstl.cpp:2176
void dereferenceInvalidIteratorError(const Token *deref, const std::string &iterName)
Definition: checkstl.cpp:2542
void invalidIteratorError(const Token *tok, const std::string &iteratorName)
Definition: checkstl.cpp:358
void negativeIndexError(const Token *tok, const ValueFlow::Value &index)
Definition: checkstl.cpp:1365
void checkMutexes()
Definition: checkstl.cpp:3255
void outOfBounds()
Accessing container out of bounds using ValueFlow.
Definition: checkstl.cpp:133
void mismatchingContainerIterator()
Definition: checkstl.cpp:855
CheckStl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
This constructor is used when running checks.
Definition: checkstl.h:52
SubstrErrorType
Definition: checkstl.h:227
void invalidContainer()
Definition: checkstl.cpp:1104
void negativeIndex()
negative index for array like containers
Definition: checkstl.cpp:1341
void dereferenceErasedError(const Token *erased, const Token *deref, const std::string &itername, bool inconclusive)
Dereferencing an erased iterator.
Definition: checkstl.cpp:394
void mismatchingContainerExpressionError(const Token *tok1, const Token *tok2)
Definition: checkstl.cpp:675
void if_find()
if (a.find(x)) - possibly incorrect condition
Definition: checkstl.cpp:1498
void stlOutOfBoundsError(const Token *tok, const std::string &num, const std::string &var, bool at)
Definition: checkstl.cpp:1333
void checkFindInsertError(const Token *tok)
Definition: checkstl.cpp:1726
void useStlAlgorithm()
Look for loops that can replaced with std algorithms.
Definition: checkstl.cpp:2874
void iterators()
Finds errors like this: for (it = foo.begin(); it != bar.end(); ++it)
Definition: checkstl.cpp:464
void string_c_strThrowError(const Token *tok)
Definition: checkstl.cpp:2158
void useStlAlgorithmError(const Token *tok, const std::string &algoName)
Definition: checkstl.cpp:2551
void outOfBoundsError(const Token *tok, const std::string &containerName, const ValueFlow::Value *containerSize, const std::string &index, const ValueFlow::Value *indexValue)
Definition: checkstl.cpp:221
void stlBoundaries()
bad condition.
Definition: checkstl.cpp:1444
void string_c_str()
Check for common mistakes when using the function string::c_str()
Definition: checkstl.cpp:1956
void mismatchingContainers()
Mismatching containers: std::find(foo.begin(), bar.end(), x)
Definition: checkstl.cpp:795
void knownEmptyContainer()
Definition: checkstl.cpp:3106
void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override
run checks, the token list is not simplified
Definition: checkstl.h:56
void globalLockGuardError(const Token *tok)
Definition: checkstl.cpp:3241
void checkDereferenceInvalidIterator()
Check for dereferencing an iterator that is invalid
Definition: checkstl.cpp:2352
void iteratorsError(const Token *tok, const std::string &containerName1, const std::string &containerName2)
Definition: checkstl.cpp:363
void redundantCondition()
Check for redundant condition 'if (ints.find(1) != ints.end()) ints.remove(123);'.
Definition: checkstl.cpp:1819
void localMutexError(const Token *tok)
Definition: checkstl.cpp:3248
void redundantIfRemoveError(const Token *tok)
Definition: checkstl.cpp:1852
void eraseIteratorOutOfBounds()
Definition: checkstl.cpp:3194
void string_c_strError(const Token *tok)
Definition: checkstl.cpp:2164
void if_findError(const Token *tok, bool str)
Definition: checkstl.cpp:1575
void string_c_strReturn(const Token *tok)
Definition: checkstl.cpp:2170
void invalidContainerLoopError(const Token *tok, const Token *loopTok, ErrorPath errorPath)
Definition: checkstl.cpp:1214
void checkFindInsert()
Definition: checkstl.cpp:1680
static std::string myName()
Definition: checkstl.h:285
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override
get error messages
Definition: checkstl.h:245
void uselessCallsEmptyError(const Token *tok)
Definition: checkstl.cpp:2336
Interface class that cppcheck uses to communicate with the checks.
Definition: check.h:59
This is an interface, which the class responsible of error logging should implement.
Definition: errorlogger.h:214
This is just a container for general settings so that we don't need to pass individual values to func...
Definition: settings.h:95
The token list that the TokenList generates is a linked-list of this class.
Definition: token.h:150
The main purpose is to tokenize the source code.
Definition: tokenize.h:46
const Settings & getSettings() const
Definition: tokenize.h:615
bool isCPP() const
Is the code CPP.
Definition: tokenize.h:69
Information about a member variable.
static const std::string emptyString
Definition: config.h:127
#define CPPCHECKLIB
Definition: config.h:35
#define nonneg
Definition: config.h:138
std::list< ErrorPathItem > ErrorPath
Definition: errortypes.h:130