diff --git a/Makefile b/Makefile index 261f73feae0..1c6973fc418 100644 --- a/Makefile +++ b/Makefile @@ -191,7 +191,6 @@ LIBOBJ = $(libcppdir)/valueflow.o \ $(libcppdir)/checkassert.o \ $(libcppdir)/checkautovariables.o \ $(libcppdir)/checkbool.o \ - $(libcppdir)/checkboost.o \ $(libcppdir)/checkbufferoverrun.o \ $(libcppdir)/checkclass.o \ $(libcppdir)/checkcondition.o \ @@ -275,7 +274,6 @@ TESTOBJ = test/fixture.o \ test/testastutils.o \ test/testautovariables.o \ test/testbool.o \ - test/testboost.o \ test/testbufferoverrun.o \ test/testcharvar.o \ test/testcheck.o \ @@ -482,9 +480,6 @@ $(libcppdir)/checkautovariables.o: lib/checkautovariables.cpp lib/addoninfo.h li $(libcppdir)/checkbool.o: lib/checkbool.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkbool.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkbool.cpp -$(libcppdir)/checkboost.o: lib/checkboost.cpp lib/check.h lib/checkboost.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h - $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkboost.cpp - $(libcppdir)/checkbufferoverrun.o: lib/checkbufferoverrun.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/astutils.h lib/check.h lib/checkbufferoverrun.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h lib/xml.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkbufferoverrun.cpp @@ -719,9 +714,6 @@ test/testautovariables.o: test/testautovariables.cpp externals/simplecpp/simplec test/testbool.o: test/testbool.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkbool.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testbool.cpp -test/testboost.o: test/testboost.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkboost.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h - $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testboost.cpp - test/testbufferoverrun.o: test/testbufferoverrun.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkbufferoverrun.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testbufferoverrun.cpp diff --git a/lib/checkboost.cpp b/lib/checkboost.cpp deleted file mode 100644 index a246426f8b5..00000000000 --- a/lib/checkboost.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2024 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 "checkboost.h" - -#include "errortypes.h" -#include "symboldatabase.h" -#include "token.h" -#include "tokenize.h" - -#include - -// Register this check class (by creating a static instance of it) -namespace { - CheckBoost instance; -} - -static const CWE CWE664(664); - -void CheckBoost::checkBoostForeachModification() -{ - logChecker("CheckBoost::checkBoostForeachModification"); - const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); - for (const Scope * scope : symbolDatabase->functionScopes) { - for (const Token *tok = scope->bodyStart->next(); tok && tok != scope->bodyEnd; tok = tok->next()) { - if (!Token::simpleMatch(tok, "BOOST_FOREACH (")) - continue; - - const Token *containerTok = tok->linkAt(1)->previous(); - if (!Token::Match(containerTok, "%var% ) {")) - continue; - - const Token *tok2 = containerTok->tokAt(2); - const Token *end = tok2->link(); - for (; tok2 != end; tok2 = tok2->next()) { - if (Token::Match(tok2, "%varid% . insert|erase|push_back|push_front|pop_front|pop_back|clear|swap|resize|assign|merge|remove|remove_if|reverse|sort|splice|unique|pop|push", containerTok->varId())) { - const Token* nextStatement = Token::findsimplematch(tok2->linkAt(3), ";", end); - if (!Token::Match(nextStatement, "; break|return|throw")) - boostForeachError(tok2); - break; - } - } - } - } -} - -void CheckBoost::boostForeachError(const Token *tok) -{ - reportError(tok, Severity::error, "boostForeachError", - "BOOST_FOREACH caches the end() iterator. It's undefined behavior if you modify the container inside.", CWE664, Certainty::normal - ); -} - -void CheckBoost::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) -{ - if (!tokenizer.isCPP()) - return; - - CheckBoost checkBoost(&tokenizer, &tokenizer.getSettings(), errorLogger); - checkBoost.checkBoostForeachModification(); -} - -void CheckBoost::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const -{ - CheckBoost c(nullptr, settings, errorLogger); - c.boostForeachError(nullptr); -} diff --git a/lib/checkboost.h b/lib/checkboost.h deleted file mode 100644 index 97eb5c3e712..00000000000 --- a/lib/checkboost.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- C++ -*- - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2024 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 . - */ - - -//--------------------------------------------------------------------------- -#ifndef checkboostH -#define checkboostH -//--------------------------------------------------------------------------- - -#include "check.h" -#include "config.h" - -#include - -class ErrorLogger; -class Settings; -class Token; -class Tokenizer; - -/// @addtogroup Checks -/// @{ - - -/** @brief %Check Boost usage */ -class CPPCHECKLIB CheckBoost : public Check { -public: - /** This constructor is used when registering the CheckClass */ - CheckBoost() : Check(myName()) {} - -private: - /** This constructor is used when running checks. */ - CheckBoost(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) {} - - /** @brief Run checks against the normal token list */ - void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override; - - /** @brief %Check for container modification while using the BOOST_FOREACH macro */ - void checkBoostForeachModification(); - - void boostForeachError(const Token *tok); - - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override; - - static std::string myName() { - return "Boost usage"; - } - - std::string classInfo() const override { - return "Check for invalid usage of Boost:\n" - "- container modification during BOOST_FOREACH\n"; - } -}; -/// @} -//--------------------------------------------------------------------------- -#endif // checkboostH diff --git a/lib/cppcheck.vcxproj b/lib/cppcheck.vcxproj index a19b770596a..3d830e2894c 100644 --- a/lib/cppcheck.vcxproj +++ b/lib/cppcheck.vcxproj @@ -36,7 +36,6 @@ - @@ -108,7 +107,6 @@ - diff --git a/lib/cppcheck.vcxproj.filters b/lib/cppcheck.vcxproj.filters index 7d69edfa230..a4c000fd9a6 100644 --- a/lib/cppcheck.vcxproj.filters +++ b/lib/cppcheck.vcxproj.filters @@ -89,9 +89,6 @@ Source Files - - Source Files - Source Files @@ -382,9 +379,6 @@ Header Files - - Header Files - Header Files diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index c22877fc1a1..e7d5b074824 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -5500,10 +5500,11 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) // if MACRO for (Token *tok = list.front(); tok; tok = tok->next()) { - if (Token::Match(tok, "if|for|while|BOOST_FOREACH %name% (")) { + if (Token::Match(tok, "if|for|while %name% (")) { if (Token::simpleMatch(tok, "for each")) { - // 'for each ( )' -> 'asm ( )' - tok->str("asm"); + // 'for each (x in y )' -> 'for (x : y)' + if (Token* in = Token::findsimplematch(tok->tokAt(2), "in", tok->linkAt(2))) + in->str(":"); tok->deleteNext(); } else if (tok->strAt(1) == "constexpr") { tok->deleteNext(); diff --git a/oss-fuzz/Makefile b/oss-fuzz/Makefile index 6ef1d053c54..6e9bf3025eb 100644 --- a/oss-fuzz/Makefile +++ b/oss-fuzz/Makefile @@ -44,7 +44,6 @@ LIBOBJ = $(libcppdir)/valueflow.o \ $(libcppdir)/checkassert.o \ $(libcppdir)/checkautovariables.o \ $(libcppdir)/checkbool.o \ - $(libcppdir)/checkboost.o \ $(libcppdir)/checkbufferoverrun.o \ $(libcppdir)/checkclass.o \ $(libcppdir)/checkcondition.o \ @@ -178,9 +177,6 @@ $(libcppdir)/checkautovariables.o: ../lib/checkautovariables.cpp ../lib/addoninf $(libcppdir)/checkbool.o: ../lib/checkbool.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkbool.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/suppressions.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkbool.cpp -$(libcppdir)/checkboost.o: ../lib/checkboost.cpp ../lib/check.h ../lib/checkboost.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h - $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkboost.cpp - $(libcppdir)/checkbufferoverrun.o: ../lib/checkbufferoverrun.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkbufferoverrun.h ../lib/color.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/suppressions.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h ../lib/xml.h $(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkbufferoverrun.cpp diff --git a/test/cfg/boost.cpp b/test/cfg/boost.cpp index 49ef2546444..771b3b964f6 100644 --- a/test/cfg/boost.cpp +++ b/test/cfg/boost.cpp @@ -19,6 +19,10 @@ #include #include #include +#include + +#include +#include BOOST_FORCEINLINE void boost_forceinline_test() {} @@ -108,6 +112,56 @@ void lock_guard_finiteLifetime(boost::mutex& m) boost::lock_guard{ m }; } +void test_BOOST_FOREACH_1(std::vector data) +{ + BOOST_FOREACH(int i, data) { + // cppcheck-suppress invalidContainerLoop + data.push_back(123); + } +} + +void test_BOOST_FOREACH_2(std::set data) +{ + BOOST_FOREACH(int i, data) { + // don't warn for std::set + data.insert(123); + } +} + +void test_BOOST_FOREACH_3(std::vector data) +{ + BOOST_FOREACH(const int& i, data) { + // cppcheck-suppress invalidContainerLoop + data.erase(data.begin()); + } +} + +// Check single line usage +void test_BOOST_FOREACH_4(std::vector data) +{ + BOOST_FOREACH(const int& i, data) + // cppcheck-suppress invalidContainerLoop + data.clear(); +} + +// Container returned as result of a function -> Be quiet +std::vector get_data(); +void test_BOOST_FOREACH_5() +{ + std::set data; + BOOST_FOREACH(const int& i, get_data()) + data.insert(i); +} + +// Break after modification (#4788) +void test_BOOST_FOREACH_6(std::vector data) +{ + BOOST_FOREACH(int i, data) { + data.push_back(123); + break; + } +} + BOOST_AUTO_TEST_SUITE(my_auto_test_suite) BOOST_AUTO_TEST_CASE(test_message_macros) @@ -127,4 +181,4 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(my_tuple_test, T, test_types_w_tuples) BOOST_TEST(sizeof(T) == 4U); } -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/testboost.cpp b/test/testboost.cpp deleted file mode 100644 index ff8b2a44655..00000000000 --- a/test/testboost.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2024 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 "checkboost.h" -#include "errortypes.h" -#include "fixture.h" -#include "helpers.h" -#include "settings.h" - -#include - -class TestBoost : public TestFixture { -public: - TestBoost() : TestFixture("TestBoost") {} - -private: - const Settings settings = settingsBuilder().severity(Severity::style).severity(Severity::performance).build(); - - void run() override { - TEST_CASE(BoostForeachContainerModification); - } - -#define check(code) check_(code, __FILE__, __LINE__) - template - void check_(const char (&code)[size], const char* file, int line) { - // Tokenize.. - SimpleTokenizer tokenizer(settings, *this); - ASSERT_LOC(tokenizer.tokenize(code), file, line); - - // Check.. - runChecks(tokenizer, this); - } - - void BoostForeachContainerModification() { - check("void f() {\n" - " vector data;\n" - " BOOST_FOREACH(int i, data) {\n" - " data.push_back(123);\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:4]: (error) BOOST_FOREACH caches the end() iterator. It's undefined behavior if you modify the container inside.\n", errout_str()); - - check("void f() {\n" - " set data;\n" - " BOOST_FOREACH(int i, data) {\n" - " data.insert(123);\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:4]: (error) BOOST_FOREACH caches the end() iterator. It's undefined behavior if you modify the container inside.\n", errout_str()); - - check("void f() {\n" - " set data;\n" - " BOOST_FOREACH(const int &i, data) {\n" - " data.erase(123);\n" - " }\n" - "}"); - ASSERT_EQUALS("[test.cpp:4]: (error) BOOST_FOREACH caches the end() iterator. It's undefined behavior if you modify the container inside.\n", errout_str()); - - // Check single line usage - check("void f() {\n" - " set data;\n" - " BOOST_FOREACH(const int &i, data)\n" - " data.clear();\n" - "}"); - ASSERT_EQUALS("[test.cpp:4]: (error) BOOST_FOREACH caches the end() iterator. It's undefined behavior if you modify the container inside.\n", errout_str()); - - // Container returned as result of a function -> Be quiet - check("void f() {\n" - " BOOST_FOREACH(const int &i, get_data())\n" - " data.insert(i);\n" - "}"); - ASSERT_EQUALS("", errout_str()); - - // Break after modification (#4788) - check("void f() {\n" - " vector data;\n" - " BOOST_FOREACH(int i, data) {\n" - " data.push_back(123);\n" - " break;\n" - " }\n" - "}"); - ASSERT_EQUALS("", errout_str()); - } -}; - -REGISTER_TEST(TestBoost) diff --git a/test/testrunner.vcxproj b/test/testrunner.vcxproj index 07cb0e82847..02054bbbb2d 100755 --- a/test/testrunner.vcxproj +++ b/test/testrunner.vcxproj @@ -49,7 +49,6 @@ - diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index bbebf933723..919f7087369 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -918,9 +918,9 @@ class TestTokenizer : public TestFixture { void foreach () { // #3690,#5154 const char code[] ="void f() { for each ( char c in MyString ) { Console::Write(c); } }"; - ASSERT_EQUALS("void f ( ) { asm ( \"char c in MyString\" ) { Console :: Write ( c ) ; } }", tokenizeAndStringify(code)); + ASSERT_EQUALS("void f ( ) { for ( char c : MyString ) { Console :: Write ( c ) ; } }", tokenizeAndStringify(code)); ASSERT_EQUALS( - "[test.cpp:1]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable c\n", + "[test.cpp:1]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable MyString\n", errout_str()); } diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index e19ea083fbc..e8f53d1224b 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -2145,7 +2145,7 @@ class TestUninitVar : public TestFixture { " static const struct ab {\n" " int a,b;\n" " int get_a() { return a; }" - " } = { 0, 0 };\n" + " } x = { 0, 0 };\n" "}", true, false); ASSERT_EQUALS("", errout_str());