From 5ac87cc57919f9fb3fe47845c3d1db63dd6705a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 4 Apr 2024 20:45:33 +0200 Subject: [PATCH] Fix #12505 (cli: Add option --check-version to pin cppcheck version) (#6121) I chose to not add it in the help output. But I don't have a strong opinion it can be added there also. This option was added for the safety certification. It could be very bad if a user runs one version of cppcheck and thinks that he runs another version. --- cli/cmdlineparser.cpp | 31 ++++++++++++++++++++++--------- cli/cmdlineparser.h | 5 +++++ releasenotes.txt | 3 ++- test/testcmdlineparser.cpp | 17 +++++++++++++++++ 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 920bede12de..bb3787db0f2 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -356,15 +356,8 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a if (std::strcmp(argv[i], "--version") == 0) { if (!loadCppcheckCfg()) return Result::Fail; - if (!mSettings.cppcheckCfgProductName.empty()) { - mLogger.printRaw(mSettings.cppcheckCfgProductName); - } else { - const char * const extraVersion = CppCheck::extraVersion(); - if (*extraVersion != '\0') - mLogger.printRaw(std::string("Cppcheck ") + CppCheck::version() + " ("+ extraVersion + ')'); - else - mLogger.printRaw(std::string("Cppcheck ") + CppCheck::version()); - } + const std::string version = getVersion(); + mLogger.printRaw(version); return Result::Exit; } } @@ -488,6 +481,17 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a mSettings.checkLibrary = true; } + else if (std::strncmp(argv[i], "--check-version=", 16) == 0) { + if (!loadCppcheckCfg()) + return Result::Fail; + const std::string actualVersion = getVersion(); + const std::string wantedVersion = argv[i] + 16; + if (actualVersion != wantedVersion) { + mLogger.printError("--check-version check failed. Aborting."); + return Result::Fail; + } + } + else if (std::strncmp(argv[i], "--checkers-report=", 18) == 0) mSettings.checkersReportFilename = argv[i] + 18; @@ -1746,6 +1750,15 @@ void CmdLineParser::printHelp() const mLogger.printRaw(oss.str()); } +std::string CmdLineParser::getVersion() const { + if (!mSettings.cppcheckCfgProductName.empty()) + return mSettings.cppcheckCfgProductName; + const char * const extraVersion = CppCheck::extraVersion(); + if (*extraVersion != '\0') + return std::string("Cppcheck ") + CppCheck::version() + " ("+ extraVersion + ')'; + return std::string("Cppcheck ") + CppCheck::version(); +} + bool CmdLineParser::isCppcheckPremium() const { if (mSettings.cppcheckCfgProductName.empty()) Settings::loadCppcheckCfg(mSettings, mSettings.supprs); diff --git a/cli/cmdlineparser.h b/cli/cmdlineparser.h index 4e41094ee10..6f3a2738932 100644 --- a/cli/cmdlineparser.h +++ b/cli/cmdlineparser.h @@ -102,6 +102,11 @@ class CmdLineParser { return mIgnoredPaths; } + /** + * Get Cppcheck version + */ + std::string getVersion() const; + protected: /** diff --git a/releasenotes.txt b/releasenotes.txt index f68333b7075..56c7500bc41 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -26,4 +26,5 @@ Other: - Added CMake option 'DISALLOW_THREAD_EXECUTOR' to control the inclusion of the executor which performs the analysis within a thread of the main process. - Removed CMake option 'USE_THREADS' in favor of 'DISALLOW_THREAD_EXECUTOR'. - Fixed crash with '--rule-file=' if some data was missing. -- '--rule-file' will now bail out if a rule could not be added or a file contains unexpected data. \ No newline at end of file +- '--rule-file' will now bail out if a rule could not be added or a file contains unexpected data. +- Add option '--check-version', you can use it to pin the cppcheck version in a script. diff --git a/test/testcmdlineparser.cpp b/test/testcmdlineparser.cpp index d01abd2d440..22a7627af05 100644 --- a/test/testcmdlineparser.cpp +++ b/test/testcmdlineparser.cpp @@ -119,6 +119,8 @@ class TestCmdlineParser : public TestFixture { TEST_CASE(versionWithCfg); TEST_CASE(versionExclusive); TEST_CASE(versionWithInvalidCfg); + TEST_CASE(checkVersionCorrect); + TEST_CASE(checkVersionIncorrect); TEST_CASE(onefile); TEST_CASE(onepath); TEST_CASE(optionwithoutfile); @@ -473,6 +475,21 @@ class TestCmdlineParser : public TestFixture { ASSERT_EQUALS("cppcheck: error: could not load cppcheck.cfg - not a valid JSON - syntax error at line 2 near: \n", logger->str()); } + void checkVersionCorrect() { + REDIRECT; + const std::string currentVersion = parser->getVersion(); + const std::string checkVersion = "--check-version=" + currentVersion; + const char * const argv[] = {"cppcheck", checkVersion.c_str(), "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(3, argv)); + } + + void checkVersionIncorrect() { + REDIRECT; + const char * const argv[] = {"cppcheck", "--check-version=Cppcheck 2.0", "file.cpp"}; + ASSERT_EQUALS_ENUM(CmdLineParser::Result::Fail, parser->parseFromArgs(3, argv)); + ASSERT_EQUALS("cppcheck: error: --check-version check failed. Aborting.\n", logger->str()); + } + void onefile() { REDIRECT; const char * const argv[] = {"cppcheck", "file.cpp"};