See More

/* * Cppcheck - A tool for static C/C++ code analysis * Copyright (C) 2007-2026 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "checkstl.h" #include "errortypes.h" #include "fixture.h" #include "helpers.h" #include "settings.h" #include "standards.h" #include "utils.h" #include #include class TestStl : public TestFixture { public: TestStl() : TestFixture("TestStl") {} private: const Settings settings = settingsBuilder().severity(Severity::warning).severity(Severity::style).severity(Severity::performance).library("std.cfg").build(); const Settings settings_i = settingsBuilder(settings).certainty(Certainty::inconclusive).build(); const Settings settingsCpp03 = settingsBuilder(settings).cpp(Standards::CPP03).build(); void run() override { mNewTemplate = true; TEST_CASE(outOfBounds); TEST_CASE(outOfBoundsSymbolic); TEST_CASE(outOfBoundsIndexExpression); TEST_CASE(outOfBoundsIterator); TEST_CASE(outOfBoundsErrorPath); TEST_CASE(iterator1); TEST_CASE(iterator2); TEST_CASE(iterator3); TEST_CASE(iterator4); TEST_CASE(iterator5); TEST_CASE(iterator6); TEST_CASE(iterator7); TEST_CASE(iterator8); TEST_CASE(iterator9); TEST_CASE(iterator10); TEST_CASE(iterator11); TEST_CASE(iterator12); TEST_CASE(iterator13); TEST_CASE(iterator14); // #8191 TEST_CASE(iterator15); // #8341 TEST_CASE(iterator16); TEST_CASE(iterator17); TEST_CASE(iterator18); TEST_CASE(iterator19); TEST_CASE(iterator20); TEST_CASE(iterator21); TEST_CASE(iterator22); TEST_CASE(iterator23); TEST_CASE(iterator24); TEST_CASE(iterator25); // #9742 TEST_CASE(iterator26); // #9176 TEST_CASE(iterator27); // #10378 TEST_CASE(iterator28); // #10450 TEST_CASE(iterator29); TEST_CASE(iterator30); TEST_CASE(iterator31); TEST_CASE(iteratorExpression); TEST_CASE(iteratorSameExpression); TEST_CASE(mismatchingContainerIterator); TEST_CASE(eraseIteratorOutOfBounds); TEST_CASE(algorithmOutOfBounds); TEST_CASE(dereference); TEST_CASE(dereference_break); // #3644 - handle "break" TEST_CASE(dereference_member); TEST_CASE(STLSize); TEST_CASE(STLSizeNoErr); TEST_CASE(negativeIndex); TEST_CASE(negativeIndexMultiline); TEST_CASE(erase1); TEST_CASE(erase2); TEST_CASE(erase3); TEST_CASE(erase4); TEST_CASE(erase5); TEST_CASE(erase6); TEST_CASE(eraseBreak); TEST_CASE(eraseContinue); TEST_CASE(eraseReturn1); TEST_CASE(eraseReturn2); TEST_CASE(eraseReturn3); TEST_CASE(eraseGoto); TEST_CASE(eraseAssign1); TEST_CASE(eraseAssign2); TEST_CASE(eraseAssign3); TEST_CASE(eraseAssign4); TEST_CASE(eraseAssignByFunctionCall); TEST_CASE(eraseErase); TEST_CASE(eraseByValue); TEST_CASE(eraseIf); TEST_CASE(eraseOnVector); TEST_CASE(pushback1); TEST_CASE(pushback2); TEST_CASE(pushback3); TEST_CASE(pushback4); TEST_CASE(pushback5); TEST_CASE(pushback6); TEST_CASE(pushback7); TEST_CASE(pushback8); TEST_CASE(pushback9); TEST_CASE(pushback10); TEST_CASE(pushback11); TEST_CASE(pushback12); TEST_CASE(pushback13); TEST_CASE(insert1); TEST_CASE(insert2); TEST_CASE(popback1); TEST_CASE(stlBoundaries1); TEST_CASE(stlBoundaries2); TEST_CASE(stlBoundaries3); TEST_CASE(stlBoundaries4); // #4364 TEST_CASE(stlBoundaries5); // #4352 TEST_CASE(stlBoundaries6); // #7106 // if (str.find("ab")) TEST_CASE(if_find); TEST_CASE(if_str_find); TEST_CASE(size1); TEST_CASE(size2); TEST_CASE(size3); TEST_CASE(size4); // #2652 - don't warn about vector/deque // Redundant conditions.. // if (ints.find(123) != ints.end()) ints.remove(123); TEST_CASE(redundantCondition1); // missing inner comparison when incrementing iterator inside loop TEST_CASE(missingInnerComparison1); TEST_CASE(missingInnerComparison2); // no FP when there is comparison TEST_CASE(missingInnerComparison3); // no FP when there is iterator shadowing TEST_CASE(missingInnerComparison4); // no FP when "break;" is used TEST_CASE(missingInnerComparison5); // Ticket #2154 - FP TEST_CASE(missingInnerComparison6); // #2643 - 'it=foo.insert(++it,0);' // catch common problems when using the string::c_str() function TEST_CASE(cstr); TEST_CASE(uselessCalls); TEST_CASE(stabilityOfChecks); // #4684 cppcheck crash in template function call TEST_CASE(dereferenceInvalidIterator); TEST_CASE(dereferenceInvalidIterator2); // #6572 TEST_CASE(dereference_auto); TEST_CASE(loopAlgoElementAssign); TEST_CASE(loopAlgoAccumulateAssign); TEST_CASE(loopAlgoContainerInsert); TEST_CASE(loopAlgoIncrement); TEST_CASE(loopAlgoConditional); TEST_CASE(loopAlgoMinMax); TEST_CASE(loopAlgoMultipleReturn); TEST_CASE(invalidContainer); TEST_CASE(invalidContainerLoop); TEST_CASE(findInsert); TEST_CASE(checkKnownEmptyContainer); TEST_CASE(checkMutexes); } struct CheckOptions { bool inconclusive = false; }; #define check(...) check_(__FILE__, __LINE__, __VA_ARGS__) template void check_(const char* file, int line, const char (&code)[size], const CheckOptions& options = make_default_obj()) { const Settings& s = options.inconclusive ? settings_i : settings; check_(file, line, code, s); } template void check_(const char* file, int line, const char (&code)[size], const Settings& s) { SimpleTokenizer tokenizer(s, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); CheckStl check; runChecks(check, tokenizer, *this); } // TODO: get rid of this void check_(const char* file, int line, const std::string& code) { // Tokenize.. SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); CheckStl check; runChecks(check, tokenizer, *this); } #define checkNormal(...) checkNormal_(__FILE__, __LINE__, __VA_ARGS__) template void checkNormal_(const char* file, int line, const char (&code)[size]) { // Tokenize.. SimpleTokenizer tokenizer(settings, *this); ASSERT_LOC(tokenizer.tokenize(code), file, line); CheckStl check; runChecks(check, tokenizer, *this); } void outOfBounds() { setMultiline(); checkNormal("bool f(const int a, const int b)\n" // #8648 "{\n" " std::cout << a << b;\n" " return true;\n" "}\n" "void f(const std::vector &v)\n" "{\n" " if(v.size() >=2 &&\n" " bar(v[2], v[3]) )\n" // v[3] is accessed " {;}\n" "}\n"); ASSERT_EQUALS("[test.cpp:9:18]: warning: Either the condition 'v.size()>=2' is redundant or size of 'v' can be 2. Expression 'v[2]' causes access out of bounds. [containerOutOfBounds]\n" "[test.cpp:8:17]: note: condition 'v.size()>=2'\n" "[test.cpp:9:18]: note: Access out of bounds\n" "[test.cpp:9:24]: warning: Either the condition 'v.size()>=2' is redundant or size of 'v' can be 2. Expression 'v[3]' causes access out of bounds. [containerOutOfBounds]\n" "[test.cpp:8:17]: note: condition 'v.size()>=2'\n" "[test.cpp:9:24]: note: Access out of bounds\n", errout_str()); checkNormal("void f() {\n" " std::string s;\n" " s[10] = 1;\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:4]: error: Out of bounds access in expression 's[10]' because 's' is empty. [containerOutOfBounds]\n", errout_str()); checkNormal("void f() {\n" " std::string s = \"abcd\";\n" " s[10] = 1;\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:4]: error: Out of bounds access in 's[10]', if 's' size is 4 and '10' is 10 [containerOutOfBounds]\n", errout_str()); checkNormal("void f(std::vector v) {\n" " v.front();\n" " if (v.empty()) {}\n" "}\n"); ASSERT_EQUALS("[test.cpp:2:12]: warning: Either the condition 'v.empty()' is redundant or expression 'v.front()' causes access out of bounds. [containerOutOfBounds]\n" "[test.cpp:3:16]: note: condition 'v.empty()'\n" "[test.cpp:2:12]: note: Access out of bounds\n", errout_str()); checkNormal("void f(std::vector v) {\n" " if (v.size() == 3) {}\n" " v[16] = 0;\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:6]: warning: Either the condition 'v.size()==3' is redundant or size of 'v' can be 3. Expression 'v[16]' causes access out of bounds. [containerOutOfBounds]\n" "[test.cpp:2:18]: note: condition 'v.size()==3'\n" "[test.cpp:3:6]: note: Access out of bounds\n", errout_str()); checkNormal("void f(std::vector v) {\n" " int i = 16;\n" " if (v.size() == 3) {\n" " v[i] = 0;\n" " }\n" "}\n"); ASSERT_EQUALS("[test.cpp:4:10]: warning: Either the condition 'v.size()==3' is redundant or size of 'v' can be 3. Expression 'v[i]' causes access out of bounds. [containerOutOfBounds]\n" "[test.cpp:3:18]: note: condition 'v.size()==3'\n" "[test.cpp:4:10]: note: Access out of bounds\n", errout_str()); checkNormal("void f(std::vector v, int i) {\n" " if (v.size() == 3 || i == 16) {}\n" " v[i] = 0;\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("void f(std::map x) {\n" " if (x.empty()) { x[1] = 2; }\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("void f(std::string s) {\n" " if (s.size() == 1) {\n" " s[2] = 0;\n" " }\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:10]: warning: Either the condition 's.size()==1' is redundant or size of 's' can be 1. Expression 's[2]' causes access out of bounds. [containerOutOfBounds]\n" "[test.cpp:2:18]: note: condition 's.size()==1'\n" "[test.cpp:3:10]: note: Access out of bounds\n", errout_str()); // Do not crash checkNormal("void a() {\n" " std::string b[];\n" " for (auto c : b)\n" " c.data();\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("std::string f(std::string x) {\n" " if (x.empty()) return {};\n" " x[0];\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("std::string f(std::string x) {\n" " if (x.empty()) return std::string{};\n" " x[0];\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("void f() {\n" " std::string s;\n" " x = s.begin() + 1;\n" "}\n"); ASSERT_EQUALS( "[test.cpp:3:17]: error: Out of bounds access in expression 's.begin()+1' because 's' is empty. [containerOutOfBounds]\n" "[test.cpp:3:17]: error: Out of bounds access in expression 's.begin()+1' because 's' is empty. [containerOutOfBounds]\n", // duplicate errout_str()); checkNormal("void f(int x) {\n" " std::string s;\n" " auto it = s.begin() + x;\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:23]: error: Out of bounds access in expression 's.begin()+x' because 's' is empty and 'x' may be non-zero. [containerOutOfBounds]\n", errout_str()); checkNormal("char fstr1(){const std::string s = \"\"; return s[42]; }\n" "wchar_t fwstr1(){const std::wstring s = L\"\"; return s[42]; }\n"); ASSERT_EQUALS("[test.cpp:1:54]: error: Out of bounds access in 's[42]', if 's' size is 6 and '42' is 42 [containerOutOfBounds]\n" "[test.cpp:2:60]: error: Out of bounds access in 's[42]', if 's' size is 6 and '42' is 42 [containerOutOfBounds]\n", errout_str()); checkNormal("char fstr1(){const std::string s = \"\"; return s[1]; }\n" "wchar_t fwstr1(){const std::wstring s = L\"\"; return s[1]; }\n"); ASSERT_EQUALS("", errout_str()); checkNormal("int f() {\n" " std::vector v;\n" " std::vector * pv = &v;\n" " return (*pv)[42];\n" "}\n"); ASSERT_EQUALS("[test.cpp:4:17]: error: Out of bounds access in expression '(*pv)[42]' because '*pv' is empty. [containerOutOfBounds]\n", errout_str()); checkNormal("void f() {\n" " std::string s;\n" " ++abc[s];\n" "}\n"); ASSERT_EQUALS("", errout_str()); // # 9274 checkNormal("char f(bool b) {\n" " const std::string s = \"\";\n" " int x = 6;\n" " if(b) ++x;\n" " return s[x];\n" "}\n"); ASSERT_EQUALS( "[test.cpp:5:13]: error: Out of bounds access in 's[x]', if 's' size is 6 and 'x' is 7 [containerOutOfBounds]\n", errout_str()); checkNormal("void f() {\n" " static const int N = 4;\n" " std::array x;\n" " x[0] = 0;\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("void f(bool b) {\n" " std::vector x;\n" " if (b)\n" " x.push_back(1);\n" " if (x.size() < 2)\n" " return;\n" " x[0] = 2;\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("void f(bool b) {\n" " std::vector v;\n" " if(v.at(b?42:0)) {}\n" "}\n"); ASSERT_EQUALS( "[test.cpp:3:12]: error: Out of bounds access in expression 'v.at(b?42:0)' because 'v' is empty. [containerOutOfBounds]\n", errout_str()); checkNormal("void f(std::vector v, bool b){\n" " if (v.size() == 1)\n" " if(v.at(b?42:0)) {}\n" "}\n"); ASSERT_EQUALS( "[test.cpp:3:16]: warning: Either the condition 'v.size()==1' is redundant or size of 'v' can be 1. Expression 'v.at(b?42:0)' causes access out of bounds. [containerOutOfBounds]\n" "[test.cpp:2:18]: note: condition 'v.size()==1'\n" "[test.cpp:3:16]: note: Access out of bounds\n", errout_str()); check("struct T {\n" " std::vector* v;\n" "};\n" "struct S {\n" " T t;\n" "};\n" "long g(S& s);\n" "int f() {\n" " std::vector ArrS;\n" " S s = { { &ArrS } };\n" " g(s);\n" " return ArrS[0];\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("struct T {\n" " std::vector* v;\n" "};\n" "struct S {\n" " std::vector t;\n" "};\n" "long g(S& s);\n" "int f() {\n" " std::vector ArrS;\n" " S s = { { { &ArrS } } };\n" " g(s);\n" " return ArrS[0];\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("struct T {\n" " std::vector* v;\n" "};\n" "struct S {\n" " std::vector<:vector>> t;\n" "};\n" "long g(S& s);\n" "int f() {\n" " std::vector ArrS;\n" " S s = { { { { &ArrS } } } };\n" " g(s);\n" " return ArrS[0];\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("struct T {\n" " std::vector* v;\n" "};\n" "struct S {\n" " T t;\n" "};\n" "long g(S& s);\n" "int f() {\n" " std::vector ArrS;\n" " S s { { &ArrS } };\n" " g(s);\n" " return ArrS[0];\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("struct T {\n" " std::vector* v;\n" "};\n" "struct S {\n" " std::vector t;\n" "};\n" "long g(S& s);\n" "int f() {\n" " std::vector ArrS;\n" " S s { { { &ArrS } } };\n" " g(s);\n" " return ArrS[0];\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("struct T {\n" " std::vector* v;\n" "};\n" "struct S {\n" " std::vector<:vector>> t;\n" "};\n" "long g(S& s);\n" "int f() {\n" " std::vector ArrS;\n" " S s { { { { &ArrS } } } };\n" " g(s);\n" " return ArrS[0];\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); checkNormal("extern void Bar(const double, const double);\n" "void f(std::vector &r, const double ) {\n" " std::vector result;\n" " double d = 0.0;\n" " const double inc = 0.1;\n" " for(unsigned int i = 0; i < 10; ++i) {\n" " result.push_back(d);\n" " d = (i + 1) * inc;\n" " }\n" " Bar(1.0, d);\n" " Bar(10U, result.size());\n" " Bar(0.0, result[0]);\n" " Bar(0.34, result[1]);\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("void f(size_t entries) {\n" " std::vector v;\n" " if (v.size() < entries + 2)\n" " v.resize(entries + 2);\n" " v[0] = 1;\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("void f(size_t entries) {\n" " std::vector v;\n" " if (v.size() < entries)\n" " v.resize(entries);\n" " v[0] = 1;\n" "}\n"); ASSERT_EQUALS("[test.cpp:5:6]: error: Out of bounds access in expression 'v[0]' because 'v' is empty. [containerOutOfBounds]\n", errout_str()); checkNormal("void f(size_t entries) {\n" " if (entries < 2) return;\n" " std::vector v;\n" " if (v.size() < entries)\n" " v.resize(entries);\n" " v[0] = 1;\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("void f(size_t entries) {\n" " if (entries == 0) return;\n" " std::vector v;\n" " if (v.size() < entries)\n" " v.resize(entries);\n" " v[0] = 1;\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("void foo(std::vector* PArr, int n) {\n" " std::vector Arr;\n" " if (!PArr)\n" " PArr = &Arr;\n" " PArr->resize(n);\n" " for (int i = 0; i < n; ++i)\n" " (*PArr)[i] = 1;\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("int f() {\n" " std::vector v;\n" " std::vector * pv = &v;\n" " return (*pv).at(42);\n" "}\n"); ASSERT_EQUALS("[test.cpp:4:20]: error: Out of bounds access in expression '(*pv).at(42)' because '*pv' is empty. [containerOutOfBounds]\n", errout_str()); checkNormal("std::string f(const char* DirName) {\n" " if (DirName == nullptr)\n" " return {};\n" " std::string Name{ DirName };\n" " if (!Name.empty() && Name.back() != '\\\\')\n" " Name += '\\\\';\n" " return Name;\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("bool f(bool b) {\n" " std::vector v;\n" " if (b)\n" " v.push_back(0);\n" " for(auto i:v)\n" " if (v[i] > 0)\n" " return true;\n" " return false;\n" "}\n"); ASSERT_EQUALS("[test.cpp:5:3]: style: Consider using std::any_of algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); checkNormal("std::vector range(int n);\n" "bool f(bool b) {\n" " std::vector v;\n" " if (b)\n" " v.push_back(1);\n" " assert(range(v.size()).size() == v.size());\n" " for(auto i:range(v.size()))\n" " if (v[i] > 0)\n" " return true;\n" " return false;\n" "}\n"); ASSERT_EQUALS("[test.cpp:7:3]: style: Consider using std::any_of algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); checkNormal("bool g();\n" "int f(int x) {\n" " std::vector v;\n" " if (g())\n" " v.emplace_back(x);\n" " const auto n = (int)v.size();\n" " for (int i = 0; i < n; ++i)\n" " if (v[i] > 0)\n" " return i;\n" " return 0;\n" "}\n"); ASSERT_EQUALS("[test.cpp:8:13]: style: Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); checkNormal("bool g();\n" "int f(int x) {\n" " std::vector v;\n" " if (g())\n" " v.emplace_back(x);\n" " const auto n = static_cast(v.size());\n" " for (int i = 0; i < n; ++i)\n" " if (v[i] > 0)\n" " return i;\n" " return 0;\n" "}\n"); ASSERT_EQUALS("[test.cpp:8:13]: style: Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n", errout_str()); checkNormal("bool g();\n" "void f(int x) {\n" " std::vector v;\n" " if (g())\n" " v.emplace_back(x);\n" " const int n = v.size();\n" " h(n);\n" " for (int i = 0; i < n; ++i)\n" " h(v[i]);\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("void foo(const std::vector &v) {\n" " if(v.size() >=1 && v[0] == 4 && v[1] == 2){}\n" "}\n"); ASSERT_EQUALS("[test.cpp:2:38]: warning: Either the condition 'v.size()>=1' is redundant or size of 'v' can be 1. Expression 'v[1]' causes access out of bounds. [containerOutOfBounds]\n" "[test.cpp:2:17]: note: condition 'v.size()>=1'\n" "[test.cpp:2:38]: note: Access out of bounds\n", errout_str()); checkNormal("int f(int x, int y) {\n" " std::vector a = {0,1,2};\n" " if(x<2)\n" " y = a[x] + 1;\n" " else\n" " y = a[x];\n" " return y;\n" "}\n"); ASSERT_EQUALS( "[test.cpp:6:14]: warning: Either the condition 'x<2' is redundant or 'x' can have the value greater or equal to 3. Expression 'a[x]' causes access out of bounds. [containerOutOfBounds]\n" "[test.cpp:3:9]: note: condition 'x<2'\n" "[test.cpp:6:14]: note: Access out of bounds\n", errout_str()); checkNormal("int f(std::vector v) {\n" " if (v.size() > 3)\n" " return v[v.size() - 3];\n" " return 0;\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("void f(std::vector v) {\n" " v[v.size() - 1];\n" " if (v.size() == 1) {}\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("void f(int n) {\n" " std::vector v = {1, 2, 3, 4};\n" " const int i = qMin(n, v.size());\n" " if (i > 1)\n" " v[i] = 1;\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("void f(std::vector& v, int i) {\n" " if (i > -1) {\n" " v.erase(v.begin() + i);\n" " if (v.empty()) {}\n" " }\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("void g(const char *, ...) { exit(1); }\n" // #10025 "void f(const char c[]) {\n" " std::vector v = get();\n" " if (v.empty())\n" " g(\"\", c[0]);\n" " return h(&v[0], v.size()); \n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("void f(int i, std::vector v) {\n" // #9157 " if (i <= (int)v.size()) {\n" " if (v[i]) {}\n" " }\n" " if (i <= static_cast(v.size())) {\n" " if (v[i]) {}\n" " }\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:14]: warning: Either the condition 'i<=(int)v.size()' is redundant or 'i' can have the value v.size(). Expression 'v[i]' causes access out of bounds. [containerOutOfBounds]\n" "[test.cpp:2:11]: note: condition 'i<=(int)v.size()'\n" "[test.cpp:3:14]: note: Access out of bounds\n" "[test.cpp:6:14]: warning: Either the condition 'i<=static_cast(v.size())' is redundant or 'i' can have the value v.size(). Expression 'v[i]' causes access out of bounds. [containerOutOfBounds]\n" "[test.cpp:5:11]: note: condition 'i<=static_cast(v.size())'\n" "[test.cpp:6:14]: note: Access out of bounds\n", errout_str()); check("template\n" "void b(Iterator d) {\n" " std::string c = \"a\";\n" " d + c.length();\n" "}\n" "void f() {\n" " std::string buf;\n" " b(buf.begin());\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:4:5]: error: Out of bounds access in expression 'd+c.length()' because 'buf' is empty. [containerOutOfBounds]\n", errout_str()); check("template\n" "void b(Iterator d) {\n" " std::string c = \"a\";\n" " sort(d, d + c.length());\n" "}\n" "void f() {\n" " std::string buf;\n" " b(buf.begin());\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("int f(const std::vector &v) {\n" " return !v.empty() ? 42 : v.back();\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS( "[test.cpp:2:36]: warning: Either the condition 'v.empty()' is redundant or expression 'v.back()' causes access out of bounds. [containerOutOfBounds]\n" "[test.cpp:2:20]: note: condition 'v.empty()'\n" "[test.cpp:2:36]: note: Access out of bounds\n", errout_str()); check("std::vector g() {\n" // #10779 " std::vector v(10);\n" " for(int i = 0; i <= 10; ++i)\n" " v[i] = 42;\n" " return v;\n" "}\n"); ASSERT_EQUALS("[test.cpp:4:10]: error: Out of bounds access in 'v[i]', if 'v' size is 10 and 'i' is 10 [containerOutOfBounds]\n", errout_str()); check("void f() {\n" " int s = 2;\n" " std::vector v(s);\n" " v[100] = 1;\n" "}\n"); ASSERT_EQUALS("[test.cpp:4:6]: error: Out of bounds access in 'v[100]', if 'v' size is 2 and '100' is 100 [containerOutOfBounds]\n", errout_str()); check("void f() {\n" " std::vector v({ 1, 2, 3 });\n" " v[100] = 1;\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:6]: error: Out of bounds access in 'v[100]', if 'v' size is 3 and '100' is 100 [containerOutOfBounds]\n", errout_str()); check("void f() {\n" " char c[] = { 1, 2, 3 };\n" " std::vector v(c, sizeof(c) + c);\n" " v[100] = 1;\n" "}\n"); ASSERT_EQUALS("[test.cpp:4:6]: error: Out of bounds access in 'v[100]', if 'v' size is 3 and '100' is 100 [containerOutOfBounds]\n", errout_str()); check("void f() {\n" " char c[] = { 1, 2, 3 };\n" " std::vector v{ c, c + sizeof(c) };\n" " v[100] = 1;\n" "}\n"); ASSERT_EQUALS("[test.cpp:4:6]: error: Out of bounds access in 'v[100]', if 'v' size is 3 and '100' is 100 [containerOutOfBounds]\n", errout_str()); check("void f() {\n" " int i[] = { 1, 2, 3 };\n" " std::vector v(i, i + sizeof(i) / 4);\n" " v[100] = 1;\n" "}\n"); ASSERT_EQUALS("[test.cpp:4:6]: error: Out of bounds access in 'v[100]', if 'v' size is 3 and '100' is 100 [containerOutOfBounds]\n", errout_str()); check("void f() {\n" // #6615 " int i[] = { 1, 2, 3 };\n" " std::vector v(i, i + sizeof(i) / sizeof(int));\n" " v[100] = 1;\n" "}\n"); TODO_ASSERT_EQUALS("test.cpp:4:error:Out of bounds access in 'v[100]', if 'v' size is 3 and '100' is 100\n", "", errout_str()); check("void f() {\n" " std::array a = {};\n" " a[10];\n" " constexpr std::array b = {};\n" " b[10];\n" " const std::array c = {};\n" " c[10];\n" " static constexpr std::array d = {};\n" " d[10];\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:6]: error: Out of bounds access in 'a[10]', if 'a' size is 10 and '10' is 10 [containerOutOfBounds]\n" "[test.cpp:5:6]: error: Out of bounds access in 'b[10]', if 'b' size is 10 and '10' is 10 [containerOutOfBounds]\n" "[test.cpp:7:6]: error: Out of bounds access in 'c[10]', if 'c' size is 10 and '10' is 10 [containerOutOfBounds]\n" "[test.cpp:9:6]: error: Out of bounds access in 'd[10]', if 'd' size is 10 and '10' is 10 [containerOutOfBounds]\n", errout_str()); check("struct test_fixed {\n" " std::array array = {};\n" " void index(int i) { array[i]; }\n" "};\n" "void f() {\n" " test_fixed x = test_fixed();\n" " x.index(10);\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:30]: error: Out of bounds access in 'array[i]', if 'array' size is 10 and 'i' is 10 [containerOutOfBounds]\n", errout_str()); check("struct test_constexpr {\n" " static constexpr std::array array = {};\n" " void index(int i) { array[i]; }\n" "};\n" "void f() {\n" " test_constexpr x = test_constexpr();\n" " x.index(10);\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:30]: error: Out of bounds access in 'array[i]', if 'array' size is 10 and 'i' is 10 [containerOutOfBounds]\n", errout_str()); checkNormal("struct A {\n" " const std::vector& v;\n" " A(const std::vector& x) : v(x)\n" " {}\n" " int f() const {\n" " return v[0];\n" " }\n" "};\n"); ASSERT_EQUALS("", errout_str()); checkNormal("struct A {\n" " static const std::vector v;\n" " int f() const {\n" " return v[0];\n" " }\n" "};\n" "const std::vector A::v = {1, 2};\n"); ASSERT_EQUALS("", errout_str()); checkNormal("struct a {\n" " std::vector g() const;\n" "};\n" "int f(const a& b) {\n" " auto c = b.g();\n" " assert(not c.empty());\n" " int d = c.front();\n" " return d;\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("std::string f() {\n" " std::map m = { { 1, \"1\" } };\n" " return m.at(1);\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("struct A {\n" " virtual void init_v(std::vector *v) = 0;\n" "};\n" "A* create_a();\n" "struct B {\n" " B() : a(create_a()) {}\n" " void init_v(std::vector *v) {\n" " a->init_v(v);\n" " }\n" " A* a;\n" "};\n" "void f() {\n" " B b;\n" " std::vector v;\n" " b.init_v(&v);\n" " v[0];\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("void f(std::vector* v) {\n" " if (v->empty())\n" " v->push_back(1);\n" " auto x = v->back();\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("template \n" "struct Foo {\n" " std::array items = {0};\n" " T maxCount = count;\n" " explicit Foo(const T& maxValue = (std::numeric_limits::max)()) : maxCount(maxValue) {}\n" " bool Set(const uint8_t idx) {\n" " if (CheckBounds(idx) && items[idx] < maxCount) {\n" " items[idx] += 1;\n" " return true;\n" " }\n" " return false;\n" " }\n" " static bool CheckBounds(const uint8_t idx) { return idx < count; }\n" "};\n" "void f() {\n" " Foo x;\n" " if (x.Set(42U)) {}\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("struct S { void g(std::span& r) const; };\n" // #11828 "int f(const S& s) {\n" " std::span t;\n" " s.g(t);\n" " return t[0];\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("char h() {\n" " std::string s;\n" " std::string_view sv(s);\n" " return s[2];\n" "}\n"); ASSERT_EQUALS("[test.cpp:4:13]: error: Out of bounds access in expression 's[2]' because 's' is empty. [containerOutOfBounds]\n", errout_str()); checkNormal("void f() {\n" // #12738 " std::vector v{ 0, 0.1 };\n" " (void)v[0];\n" "}\n"); ASSERT_EQUALS("", errout_str()); checkNormal("int f(const std::vector& v) {\n" // #8983 " return v[2];\n" "}\n" "int g() {\n" " return f({});\n" "}\n" "int h() {\n" " return f({ 1, 2 });\n" "}\n"); ASSERT_EQUALS("[test.cpp:2:13]: error: Out of bounds access in 'v[2]', if 'v' size is 2 and '2' is 2 [containerOutOfBounds]\n" "[test.cpp:2:13]: error: Out of bounds access in expression 'v[2]' because 'v' is empty. [containerOutOfBounds]\n", errout_str()); checkNormal("int f(int x, const std::vector& v) {\n" " return x + v[0];\n" "}\n" "int g() {\n" " return f(1, {});\n" "}\n"); ASSERT_EQUALS("[test.cpp:2:17]: error: Out of bounds access in expression 'v[0]' because 'v' is empty. [containerOutOfBounds]\n", errout_str()); checkNormal("bool f(const std::string_view s) { return s[500] == 'x'; }\n" // #12046 "bool g() { return f(\" \"); }\n"); ASSERT_EQUALS("[test.cpp:1:44]: error: Out of bounds access in 's[500]', if 's' size is 1 and '500' is 500 [containerOutOfBounds]\n", errout_str()); checkNormal("int main() {\n" // #14342 " const int a[] = { 1, 2, 3 };\n" " std::span x{ a };\n" " return x[3];\n" "}\n"); ASSERT_EQUALS("[test.cpp:4:13]: error: Out of bounds access in 'x[3]', if 'x' size is 1 and '3' is 3 [containerOutOfBounds]\n", errout_str()); checkNormal("int main() {\n" " const char a[] = \"abc\";\n" " std::string_view x{ a };\n" " return x[5];\n" "}\n"); ASSERT_EQUALS("[test.cpp:4:13]: error: Out of bounds access in 'x[5]', if 'x' size is 4 and '5' is 5 [containerOutOfBounds]\n", errout_str()); checkNormal("int f(const std::string& v) {\n" " return v[2];\n" "}\n" "int main() {\n" " std::string_view x{ \"a\" };\n" " return f(std::string(x));\n" "}\n"); ASSERT_EQUALS("[test.cpp:2:13]: error: Out of bounds access in 'v[2]', if 'v' size is 1 and '2' is 2 [containerOutOfBounds]\n", errout_str()); checkNormal("std::string f(const std::string& str) {\n" // do not warn, the copy has the same size as 'str' " std::string outStr = str;\n" " if (!outStr.empty())\n" " outStr[0] = 'a';\n" " for (int i = 0; i < str.size(); ++i) {\n" " if (outStr[i] == '_')\n" " outStr[i] = ' ';\n" " }\n" " return outStr;\n" "}\n"); ASSERT_EQUALS("", errout_str()); } void outOfBoundsSymbolic() { check("void foo(std::string textline, int col) {\n" " if(col > textline.size())\n" " return false;\n" " int x = textline[col];\n" "}\n"); ASSERT_EQUALS( "[test.cpp:2:12] -> [test.cpp:4:21]: (warning) Either the condition 'col>textline.size()' is redundant or 'col' can have the value textline.size(). Expression 'textline[col]' causes access out of bounds. [containerOutOfBounds]\n", errout_str()); check("void f(const std::vector& v) {\n" // #12742 " for (unsigned i = 0; i < v.size();)\n" " (void)v[i++];\n" "}\n"); ASSERT_EQUALS("", errout_str()); } void outOfBoundsIndexExpression() { setMultiline(); checkNormal("void f(std::string s) {\n" " s[s.size()] = 1;\n" "}\n"); ASSERT_EQUALS("[test.cpp:2:3]: error: Out of bounds access of s, index 's.size()' is out of bounds. [containerOutOfBoundsIndexExpression]\n", errout_str()); checkNormal("void f(std::string s) {\n" " s[s.size()+1] = 1;\n" "}\n"); ASSERT_EQUALS("[test.cpp:2:3]: error: Out of bounds access of s, index 's.size()+1' is out of bounds. [containerOutOfBoundsIndexExpression]\n", errout_str()); checkNormal("void f(std::string s) {\n" " s[1+s.size()] = 1;\n" "}\n"); ASSERT_EQUALS("[test.cpp:2:3]: error: Out of bounds access of s, index '1+s.size()' is out of bounds. [containerOutOfBoundsIndexExpression]\n", errout_str()); checkNormal("void f(std::string s) {\n" " s[x*s.size()] = 1;\n" "}\n"); ASSERT_EQUALS("[test.cpp:2:3]: error: Out of bounds access of s, index 'x*s.size()' is out of bounds. [containerOutOfBoundsIndexExpression]\n", errout_str()); checkNormal("bool f(std::string_view& sv) {\n" // #10031 " return sv[sv.size()] == '\\0';\n" "}\n"); ASSERT_EQUALS("[test.cpp:2:12]: error: Out of bounds access of sv, index 'sv.size()' is out of bounds. [containerOutOfBoundsIndexExpression]\n", errout_str()); } void outOfBoundsIterator() { check("int f() {\n" " std::vector v;\n" " auto it = v.begin();\n" " return *it;\n" "}\n"); ASSERT_EQUALS("[test.cpp:4:13]: (error) Out of bounds access in expression 'it' because 'v' is empty. [containerOutOfBounds]\n", errout_str()); check("int f() {\n" " std::vector v;\n" " v.push_back(0);\n" " auto it = v.begin() + 1;\n" " return *it;\n" "}\n"); ASSERT_EQUALS("[test.cpp:5:13]: (error) Out of bounds access in 'it', if 'v' size is 1 and 'it' is at position 1 from the beginning [containerOutOfBounds]\n", errout_str()); check("int f() {\n" " std::vector v;\n" " v.push_back(0);\n" " auto it = v.end() - 1;\n" " return *it;\n" "}\n"); ASSERT_EQUALS("", errout_str()); check("int f() {\n" " std::vector v;\n" " v.push_back(0);\n" " auto it = v.end() - 2;\n" " return *it;\n" "}\n"); ASSERT_EQUALS("[test.cpp:5:13]: (error) Out of bounds access in 'it', if 'v' size is 1 and 'it' is at position 2 from the end [containerOutOfBounds]\n", errout_str()); check("void g(int);\n" "void f(std::vector x) {\n" " std::map m;\n" " if (!m.empty()) {\n" " g(m.begin()->second);\n" " }\n" "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " std::vector vec;\n" " std::vector::iterator it = vec.begin();\n" " *it = 1;\n" "}\n"); ASSERT_EQUALS("[test.cpp:4:6]: (error) Out of bounds access in expression 'it' because 'vec' is empty. [containerOutOfBounds]\n", errout_str()); check("void f() {\n" " std::vector vec;\n" " auto it = vec.begin();\n" " *it = 1;\n" "}\n"); ASSERT_EQUALS("[test.cpp:4:6]: (error) Out of bounds access in expression 'it' because 'vec' is empty. [containerOutOfBounds]\n", errout_str()); } void outOfBoundsErrorPath() { setMultiline(); Settings s = settings; s.templateLocation = "{file}:{line}:note:{info}"; check("int f(int i) {\n" " std::string s = \"abc\";\n" " if (i > 5)\n" " return 0;\n" " return s[i];\n" "}\n", s); ASSERT_EQUALS("[test.cpp:5:13]: warning: Either the condition 'i>5' is redundant or 'i' can have the value 5. Expression 's[i]' causes access out of bounds. [containerOutOfBounds]\n" "[test.cpp:3:11]: note: Assuming that condition 'i>5' is not redundant\n" "[test.cpp:5:13]: note: Access out of bounds\n", errout_str()); check("void f(std::vector& v) {\n" " std::vector::iterator it;\n" " for (it = v.begin(); it != v.end(); ++it) {\n" " if (*it == 0)\n" " break;\n" " }\n" " v.erase(it);\n" "}\n", s); ASSERT_EQUALS("[test.cpp:4:13]: style: Consider using std::find_if algorithm instead of a raw loop. [useStlAlgorithm]\n" "[test.cpp:7:7]: warning: Either the condition is redundant or function 'erase()' is called on the iterator 'it' which is out of bounds. [eraseIteratorOutOfBoundsCond]\n" "[test.cpp:3:29]: note: Assuming that condition 'it!=v.end()' is not redundant\n" "[test.cpp:7:7]: note: Either the condition is redundant or function 'erase()' is called on the iterator 'it' which is out of bounds.\n", errout_str()); } void iterator1() { check("void f()\n" "{\n" " std::list l1;\n" " std::list l2;\n" " for (std::list::iterator it = l1.begin(); it != l2.end(); ++it)\n" " { }\n" "}\n"); ASSERT_EQUALS("[test.cpp:5:40]: (error) Iterators of different containers 'l1' and 'l2' are used together. [mismatchingContainers]\n", errout_str()); check("void f()\n" "{\n" " std::list l1;\n" " std::list l2;\n" " for (std::list::iterator it = l1.begin(); l2.end() != it; ++it)\n" " { }\n" "}\n"); ASSERT_EQUALS("[test.cpp:5:52]: (error) Iterators of different containers 'l2' and 'l1' are used together. [mismatchingContainers]\n", errout_str()); check("struct C { std::list l1; void func(); };\n" "void C::func() {\n" " std::list::iterator it;\n" " for (it = l1.begin(); it != l1.end(); ++it) { }\n" " C c;\n" " for (it = c.l1.begin(); it != c.l1.end(); ++it) { }\n" "}\n"); ASSERT_EQUALS("", errout_str()); // Same check with reverse iterator check("void f()\n" "{\n" " std::list l1;\n" " std::list l2;\n" " for (std::list::const_reverse_iterator it = l1.rbegin(); it != l2.rend(); ++it)\n" " { }\n" "}\n"); ASSERT_EQUALS("[test.cpp:5:54]: (error) Iterators of different containers 'l1' and 'l2' are used together. [mismatchingContainers]\n", errout_str()); } void iterator2() { check("void foo()\n" "{\n" " std::list l1;\n" " std::list l2;\n" " std::list::iterator it = l1.begin();\n" " while (it != l2.end())\n" " {\n" " ++it;\n" " }\n" "}\n"); ASSERT_EQUALS("[test.cpp:5:35]: (error) Iterators of different containers 'l1' and 'l2' are used together. [mismatchingContainers]\n", errout_str()); check("void foo()\n" "{\n" " std::list l1;\n" " std::list l2;\n" " std::list::iterator it = l1.begin();\n" " while (l2.end() != it)\n" " {\n" " ++it;\n" " }\n" "}\n"); ASSERT_EQUALS("[test.cpp:6:12]: (error) Iterators of different containers 'l2' and 'l1' are used together. [mismatchingContainers]\n", errout_str()); } void iterator3() { check("void foo()\n" "{\n" " std::list l1;\n" " std::list l2;\n" " std::list::iterator it = l1.begin();\n" " l2.insert(it, 0);\n" "}\n"); ASSERT_EQUALS("[test.cpp:6:5]: (error) Same iterator is used with different containers 'l1' and 'l2'. [iterators1]\n" "[test.cpp:6:5]: (error) Iterator 'it' referring to container 'l1' is used with container 'l2'. [mismatchingContainerIterator]\n", errout_str()); check("void foo() {\n" // #5803 " std::list l1;\n" " std::list l2;\n" " std::list::iterator it = l1.begin();\n" " l2.insert(it, l1.end());\n" "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" // #7658 " std::list l1;\n" " std::list l2;\n" " std::list::iterator it = l1.begin();\n" " std::list::iterator end = l1.end();\n" " l2.insert(it, end);\n" "}\n"); ASSERT_EQUALS("", errout_str()); // only warn for insert when there are preciself 2 arguments. check("void foo() {\n" " std::list l1;\n" " std::list l2;\n" " std::list::iterator it = l1.begin();\n" " l2.insert(it);\n" "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " std::list l1;\n" " std::list l2;\n" " std::list::iterator it = l1.begin();\n" " l2.insert(it,0,1);\n" "}\n"); ASSERT_EQUALS("", errout_str()); } void iterator4() { check("void foo(std::vector<:string> &test)\n" "{\n" " std::set result;\n" " for (std::vector<:string>::const_iterator cit = test.begin();\n" " cit != test.end();\n" " ++cit)\n" " {\n" " result.insert(cit->size());\n" " }\n" "}\n"); ASSERT_EQUALS("", errout_str()); } void iterator5() { check("void foo(std::vector ints1, std::vector ints2)\n" "{\n" " std::vector::iterator it = std::find(ints1.begin(), ints2.end(), 22);\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:47]: (error) Iterators of different containers 'ints1' and 'ints2' are used together. [mismatchingContainers]\n", errout_str()); } void iterator6() { // Ticket #1357 check("void foo(const std::set &ints1)\n" "{\n" " std::set ints2;\n" " std::set::iterator it1 = ints1.begin();\n" " std::set::iterator it2 = ints1.end();\n" " ints2.insert(it1, it2);\n" "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(const std::set &ints1)\n" "{\n" " std::set ints2;\n" " std::set::iterator it1 = ints1.begin();\n" " std::set::iterator it2 = ints2.end();\n" " ints2.insert(it1, it2);\n" "}\n"); TODO_ASSERT_EQUALS("[test.cpp:6]: (error) Iterators of different containers are used together.\n", "", errout_str()); } void iterator7() { check("void foo(std::vector ints1, std::vector ints2)\n" "{\n" " std::vector::iterator it = std::inplace_merge(ints1.begin(), std::advance(ints1.rbegin(), 5), ints2.end());\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:56]: (error) Iterators of different containers 'ints1' and 'ints2' are used together. [mismatchingContainers]\n", errout_str()); check("void foo(std::vector ints1, std::vector ints2)\n" "{\n" " std::vector::iterator it = std::inplace_merge(ints1.begin(), std::advance(ints2.rbegin(), 5), ints1.end());\n" "}\n"); ASSERT_EQUALS("", errout_str()); } void iterator8() { check("void foo(std::vector ints1, std::vector ints2)\n" "{\n" " std::vector::iterator it = std::find_first_of(ints1.begin(), ints2.end(), ints1.begin(), ints1.end());\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:56]: (error) Iterators of different containers 'ints1' and 'ints2' are used together. [mismatchingContainers]\n", errout_str()); check("void foo(std::vector ints1, std::vector ints2)\n" "{\n" " std::vector::iterator it = std::find_first_of(ints1.begin(), ints1.end(), ints2.begin(), ints1.end());\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:84]: (error) Iterators of different containers 'ints2' and 'ints1' are used together. [mismatchingContainers]\n", errout_str()); check("void foo(std::vector ints1, std::vector ints2)\n" "{\n" " std::vector::iterator it = std::find_first_of(foo.bar.begin(), foo.bar.end()-6, ints2.begin(), ints1.end());\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:90]: (error) Iterators of different containers 'ints2' and 'ints1' are used together. [mismatchingContainers]\n", errout_str()); check("void foo(std::vector ints1, std::vector ints2)\n" "{\n" " std::vector::iterator it = std::find_first_of(ints1.begin(), ints1.end(), ints2.begin(), ints2.end());\n" "}\n"); ASSERT_EQUALS("", errout_str()); // #6839 check("void f(const std::wstring& a, const std::wstring& b) {\n" " const std::string tp1 = std::string(a.begin(), b.end());\n" " const std::wstring tp2 = std::string(b.begin(), a.end());\n" " const std::u16string tp3(a.begin(), b.end());\n" " const std::u32string tp4(b.begin(), a.end());\n" " const std::string fp1 = std::string(a.begin(), a.end());\n" " const std::string tp2(a.begin(), a.end());\n" "}\n"); ASSERT_EQUALS( // TODO "[test.cpp:2]: (error) Iterators of different containers are used together.\n" // TODO "[test.cpp:3]: (error) Iterators of different containers are used together.\n" "[test.cpp:4:26]: (error) Iterators of different containers 'tp3' and 'a' are used together. [mismatchingContainers]\n" "[test.cpp:5:26]: (error) Iterators of different containers 'tp4' and 'b' are used together. [mismatchingContainers]\n", errout_str()); } void iterator9() { // Ticket #1600 check("void foo(std::vector &r)\n" "{\n" " std::vector::iterator aI = r.begin();\n" " while(aI != r.end())\n" " {\n" " if (*aI == 0)\n" " {\n" " r.insert(aI, 42);\n" " return;\n" " }\n" " ++aI;\n" " }\n" "}\n"); ASSERT_EQUALS("", errout_str()); // Ticket #2481 check("void foo(std::vector &r)\n" "{\n" " std::vector::iterator aI = r.begin();\n" " while(aI != r.end())\n" " {\n" " if (*aI == 0)\n" " {\n" " r.insert(aI, 42);\n" " break;\n" " }\n" " ++aI;\n" " }\n" "}\n"); ASSERT_EQUALS("", errout_str()); // Execution path checking.. check("void foo(std::vector &r, int c)\n" "{\n" " std::vector::iterator aI = r.begin();\n" " while(aI != r.end())\n" " {\n" " if (*aI == 0)\n" " {\n" " r.insert(aI, 42);\n" " if (c)\n" " {\n" " return;\n" " }\n" " }\n" " ++aI;\n" " }\n" "}\n"); TODO_ASSERT_EQUALS("[test.cpp:14] (error) After insert(), the iterator 'aI' may be invalid.", "", errout_str()); } void iterator10() { // Ticket #1679 check("void foo()\n" "{\n" " std::set s1;\n" " std::set s2;\n" " for (std::set::iterator it = s1.begin(); it != s1.end(); ++it)\n" " {\n" " if (true) { }\n" " if (it != s2.end()) continue;\n" " }\n" "}\n"); ASSERT_EQUALS("[test.cpp:5:39]: (error) Iterators of different containers 's1' and 's2' are used together. [mismatchingContainers]\n", errout_str()); } void iterator11() { // Ticket #3433 check("int main() {\n" " map myMap;\n" " vector myVector;\n" " for(vector::iterator x = myVector.begin(); x != myVector.end(); x++)\n" " myMap.erase(*x);\n" "}\n"); ASSERT_EQUALS("", errout_str()); } void iterator12() { // Ticket #3201 check("void f() {\n" " std::map map1;\n" " std::map map2;\n" " std::map::const_iterator it = map1.find(123);\n" " if (it == map2.end()) { }\n" "}\n"); ASSERT_EQUALS("[test.cpp:4:45]: (error) Iterators of different containers 'map1' and 'map2' are used together. [mismatchingContainers]\n", errout_str()); check("void f() {\n" " std::map map1;\n" " std::map map2;\n" " std::map::const_iterator it = map1.find(123);\n" " if (map2.end() == it) { }\n" "}\n"); ASSERT_EQUALS("[test.cpp:5:9]: (error) Iterators of different containers 'map2' and 'map1' are used together. [mismatchingContainers]\n", errout_str()); check("void f(std::string &s) {\n" " int pos = s.find(x);\n" " s.erase(pos);\n" " s.erase(pos);\n" "}\n"); ASSERT_EQUALS("", errout_str()); } void iterator13() { check("void f() {\n" " std::vector a;\n" " std::vector t;\n" " std::vector::const_iterator it;\n" " it = a.begin();\n" " while (it!=a.end())\n" " ++it;\n" " it = t.begin();\n" " while (it!=a.end())\n" " ++it;\n" "}\n"); ASSERT_EQUALS("[test.cpp:8:10]: (error) Iterators of different containers 't' and 'a' are used together. [mismatchingContainers]\n", errout_str()); // #4062 check("void f() {\n" " std::vector a;\n" " std::vector t;\n" " std::vector::const_iterator it;\n" " it = a.begin();\n" " while (it!=a.end())\n" " ++it;\n" " it = t.begin();\n" " while (it!=t.end())\n" " ++it;\n" "}\n"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " std::vector a;\n" " std::vector t;\n" " std::vector::const_iterator it;\n" " if(z)\n" " it = a.begin();\n" " else\n" " it = t.begin();\n" " while (z && it!=a.end())\n" " ++it;\n" " while (!z && it!=t.end())\n" " ++it;\n" "}\n"); ASSERT_EQUALS("", errout_str()); } void iterator14() { check("void f() {\n" " std::map x;\n" " std::map::const_iterator it;\n" " for (it = x.find(0)->second.begin(); it != x.find(0)->second.end(); ++it) {}\n" "}\n"); ASSERT_EQUALS("", errout_str()); } void iterator15() { check("void f(C1* x, std::list a) {\n" " std::list::iterator pos = a.begin();\n" " for(pos = x[0]->plist.begin(); pos != x[0]->plist.end(); ++pos) {}\n" "}\n"); ASSERT_EQUALS("", errout_str()); } void iterator16() { check("void foo()\n" "{\n" " std::list l1;\n" " std::list l2;\n" " std::list::iterator it1 = l1.begin();\n" " std::list::iterator it2 = l2.end();\n" " while (it1 != it2)\n" " {\n" " ++it1;\n" " }\n" "}\n"); ASSERT_EQUALS("[test.cpp:5:36]: (error) Iterators of different containers 'l1' and 'l2' are used together. [mismatchingContainers]\n", errout_str()); check("void foo()\n" "{\n" " std::list l1;\n" " std::list l2;\n" " std::list::iterator it1 = l1.end();\n" " std::list::iterator it2 = l2.begin();\n" " while (it2 != it1)\n" " {\n" " ++it2;\n" " }\n" "}\n"); ASSERT_EQUALS("[test.cpp:6:36]: (error) Iterators of different containers 'l2' and 'l1' are used together. [mismatchingContainers]\n", errout_str()); check("void foo()\n" "{\n" " std::list l1;\n" " std::list l2;\n" " std::list::iterator it2 = l2.end();\n" " std::list::iterator it1 = l1.begin();\n" " while (it1 != it2)\n" " {\n" " ++it1;\n" " }\n" "}\n"); ASSERT_EQUALS("[test.cpp:6:36]: (error) Iterators of different containers 'l1' and 'l2' are used together. [mismatchingContainers]\n", errout_str()); check("void foo()\n" "{\n" " std::set l1;\n" " std::set l2(10, 4);\n" " std::set::iterator it1 = l1.begin();\n" " std::set::iterator it2 = l2.find(4);\n" " while (it1 != it2)\n" " {\n" " ++it1;\n" " }\n" "}\n"); ASSERT_EQUALS("[test.cpp:5:35]: (error) Iterators of different containers 'l1' and 'l2' are used together. [mismatchingContainers]\n", errout_str()); } void iterator17() { check("void foo()\n" "{\n" " std::list l1;\n" " std::list l2;\n" " std::list::iterator it1 = l1.begin();\n" " std::list::iterator it2 = l1.end();\n" " { it2 = l2.end(); }\n" " while (it1 != it2)\n" " {\n" " ++it1;\n" " }\n" "}\n"); ASSERT_EQUALS("[test.cpp:5:36]: (error) Iterators of different containers 'l1' and 'l2' are used together. [mismatchingContainers]\n", errout_str()); check("void foo()\n" "{\n" " std::list l1;\n" " std::list l2;\n" " std::list::iterator it1 = l1.begin();\n" " std::list::iterator it2 = l1.end();\n" " while (it1 != it2)\n" " {\n" " ++it1;\n" " }\n" " it2 = l2.end();\n" "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" " std::list l1;\n" " std::list l2;\n" " std::list::iterator it1 = l1.begin();\n" " std::list::iterator it2 = l1.end();\n" " it1 = l2.end();\n" " it1 = l1.end();\n" " if (it1 != it2)\n" " {\n" " ++it1;\n" " }\n" "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo()\n" "{\n" " std::list l1;\n" " std::list l2;\n" " std::list::iterator it1 = l1.begin();\n" " std::list::iterator it2 = l1.end();\n" " { it2 = l2.end(); }\n" " it2 = l1.end();\n" " { it2 = l2.end(); }\n" " while (it1 != it2)\n" " {\n" " ++it1;\n" " }\n" "}\n"); ASSERT_EQUALS("[test.cpp:5:36]: (error) Iterators of different containers 'l1' and 'l2' are used together. [mismatchingContainers]\n", errout_str()); } void iterator18() { check("void foo(std::list l1, std::list l2)\n" "{\n" " std::list::iterator it1 = l1.begin();\n" " std::list::iterator it2 = l1.end();\n" " while (++it1 != --it2)\n" " {\n" " }\n" "}\n"); ASSERT_EQUALS("", errout_str()); check("void foo(std::list l1, std::list l2)\n" "{\n" " std::list