From 57d1196386ffee93d1946f34fb105d64ae5e1742 Mon Sep 17 00:00:00 2001 From: PKEuS Date: Sat, 21 Nov 2015 20:24:30 +0100 Subject: [PATCH] Replaced CheckNonReentrantFunctions and CheckObsoleteFunctions by generic CheckFunctions which is based on Library (#6529) --- cfg/posix.cfg | 610 +++++++++++++++++- cfg/std.cfg | 5 +- lib/checkfunctions.cpp | 71 ++ ...nreentrantfunctions.h => checkfunctions.h} | 45 +- lib/checknonreentrantfunctions.cpp | 105 --- lib/checkobsolescentfunctions.cpp | 76 --- lib/checkobsolescentfunctions.h | 152 ----- lib/cppcheck.vcxproj | 6 +- lib/cppcheck.vcxproj.filters | 18 +- lib/library.cpp | 50 ++ lib/library.h | 11 + lib/standards.h | 27 + ...lescentfunctions.cpp => testfunctions.cpp} | 154 ++++- test/testgarbage.cpp | 6 + test/testlibrary.cpp | 37 ++ test/testnonreentrantfunctions.cpp | 132 ---- test/testrunner.vcxproj | 3 +- test/testrunner.vcxproj.filters | 9 +- 18 files changed, 963 insertions(+), 554 deletions(-) create mode 100644 lib/checkfunctions.cpp rename lib/{checknonreentrantfunctions.h => checkfunctions.h} (57%) delete mode 100644 lib/checknonreentrantfunctions.cpp delete mode 100644 lib/checkobsolescentfunctions.cpp delete mode 100644 lib/checkobsolescentfunctions.h rename test/{testobsolescentfunctions.cpp => testfunctions.cpp} (50%) delete mode 100644 test/testnonreentrantfunctions.cpp diff --git a/cfg/posix.cfg b/cfg/posix.cfg index d335b30e3..381e8b071 100644 --- a/cfg/posix.cfg +++ b/cfg/posix.cfg @@ -19,6 +19,8 @@ + + 0: @@ -213,11 +215,13 @@ false - 0:999999 + + Obsolescent function 'usleep' called. It is recommended to use 'nanosleep' or 'setitimer' instead. +The obsolescent function 'usleep' is called. POSIX.1-2001 declares usleep() function obsolescent and POSIX.1-2008 removes it. It is recommended that new applications use the 'nanosleep' or 'setitimer' function. @@ -277,23 +281,168 @@ false + + + + + + + + false + + + Non reentrant function 'getrpcent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getrpcent_r'. + + + + false + + + + + + + Non reentrant function 'getrpcbyname' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getrpcbyname_r'. + + + + false + + Non reentrant function 'getrpcbynumber' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getrpcbynumber_r'. + + + + false + + + Non reentrant function 'getprotoent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getprotoent_r'. + + + + false + + + + + + + Non reentrant function 'getprotobyname' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getprotobyname_r'. + + + + false + + + + + + Non reentrant function 'getprotobynumber' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getprotobynumber_r'. + + + + false + + + Non reentrant function 'getservent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getservent_r'. + + + + false + + + + + + + + + + Non reentrant function 'getservbyname' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getservbyname_r'. + + + + false + + + + + + + + + Non reentrant function 'getservbyport' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getservbyport_r'. + + + + false + + + Non reentrant function 'getnetent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getnetent_r'. + + + + false + + + + + + + Non reentrant function 'getnetbyname' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getnetbyname_r'. + + + + false + + + + + + + + + Non reentrant function 'getnetbyaddr' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getnetbyaddr_r'. + + + + false + + + Non reentrant function 'gethostent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'gethostent_r'. false - + + + + + + + + + false + + + + + + + + Non reentrant function 'gethostbyname2' called. For threadsafe applications it is recommended to use the reentrant replacement function 'gethostbyname2_r'. false + @@ -305,6 +454,7 @@ + @@ -560,6 +710,7 @@ + @@ -735,6 +886,7 @@ + false @@ -1166,14 +1318,16 @@ false + false - + + @@ -1384,8 +1538,9 @@ false - + + @@ -1433,21 +1588,38 @@ - false + + Non reentrant function 'getpwent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getpwent_r'. - - false + false + + Non reentrant function 'getpwnam' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getpwnam_r'. + + + + + false + + + + + + + + + Non reentrant function 'strtok' called. For threadsafe applications it is recommended to use the reentrant replacement function 'strtok_r'. - + false + @@ -1470,11 +1642,12 @@ - - false + false + + Non reentrant function 'getpwuid' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getpwuid_r'. @@ -1672,6 +1845,7 @@ + @@ -1689,6 +1863,7 @@ + @@ -1703,6 +1878,7 @@ + @@ -1777,22 +1953,42 @@ false - + - - + + false + Non reentrant function 'localtime' called. For threadsafe applications it is recommended to use the reentrant replacement function 'localtime_r'. + + + + false + + + + + + + + false + + + + + + Non reentrant function 'readdir' called. For threadsafe applications it is recommended to use the reentrant replacement function 'readdir_r'. + false @@ -1852,6 +2048,7 @@ + @@ -1864,6 +2061,7 @@ + @@ -1877,6 +2075,17 @@ + + + + false + + + + + + Non reentrant function 'gmtime' called. For threadsafe applications it is recommended to use the reentrant replacement function 'gmtime_r'. + @@ -1926,6 +2135,380 @@ + + + false + + + + + + + + + false + + + + + + + + + + + + + Obsolescent function 'makecontext' called. Applications are recommended to be rewritten to use POSIX threads. + + + + false + + + + + + + + Obsolescent function 'swapcontext' called. Applications are recommended to be rewritten to use POSIX threads. + + + + false + + + + + Obsolescent function 'getcontext' called. Applications are recommended to be rewritten to use POSIX threads. + + + + false + + + + + + + + + + + + false + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + false + + + + + + + + + false + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + false + + + + + + + + + + + + + + false + + + + + + + + + + + + false + + + + + + false + + + + + + + + + + + + + + false + + + + + + + + + + + + + false + + + + + + + + + + + Non reentrant function 'tempnam' called. For threadsafe applications it is recommended to use the reentrant replacement function 'tempnam_r'. + + + + false + + + + + + + + + + + Non reentrant function 'crypt' called. For threadsafe applications it is recommended to use the reentrant replacement function 'crypt_r'. + + + + false + + + + + + Non reentrant function 'ttyname' called. For threadsafe applications it is recommended to use the reentrant replacement function 'ttyname_r'. + + + + false + + + + + + + Non reentrant function 'getspnam' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getspnam_r'. + + + + false + + + Non reentrant function 'getspent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getspent_r'. + + + + false + + + + + + + Non reentrant function 'fgetspent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'fgetspent_r'. + + + + false + + + + + + + Non reentrant function 'sgetspent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'sgetspent_r'. + + + + false + + + + + + + Non reentrant function 'fgetpwent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'fgetpwent_r'. + + + + false + + + Non reentrant function 'getgrent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getgrent_r'. + + + + false + + + + + + + Non reentrant function 'fgetgrent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'fgetgrent_r'. + + + + false + + + + + + + + + + + Non reentrant function 'getnetgrent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getnetgrent_r'. + + + + false + + + + + + + Non reentrant function 'getgrnam' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getgrnam_r'. + + + + false + + + + + + Non reentrant function 'getgrgid' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getgrgid_r'. + + + + false + + + Non reentrant function 'getlogin' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getlogin_r'. + + + + false + + + Non reentrant function 'ctermid' called. For threadsafe applications it is recommended to use the reentrant replacement function 'ctermid_r'. + strdup strndup @@ -1956,6 +2539,7 @@ popen pclose + diff --git a/cfg/std.cfg b/cfg/std.cfg index 95791a051..2864d6ea3 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -92,6 +92,7 @@ + @@ -1435,12 +1436,14 @@ - + false + Obsolete function 'gets' called. It is recommended to use 'fgets' instead. +The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun if the input data exceeds the size of the buffer. It is recommended to use the function 'fgets' instead. diff --git a/lib/checkfunctions.cpp b/lib/checkfunctions.cpp new file mode 100644 index 000000000..207737011 --- /dev/null +++ b/lib/checkfunctions.cpp @@ -0,0 +1,71 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2015 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 . + */ + +//--------------------------------------------------------------------------- +// Check functions +//--------------------------------------------------------------------------- + +#include "checkfunctions.h" +#include "symboldatabase.h" + +//--------------------------------------------------------------------------- + + +// Register this check class (by creating a static instance of it) +namespace { + CheckFunctions instance; +} + +void CheckFunctions::check() +{ + const bool checkAlloca = (_settings->standards.c >= Standards::C99 && _tokenizer->isC()) || _settings->standards.cpp >= Standards::CPP11; + + const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); + for (unsigned int i = 0; i < symbolDatabase->functionScopes.size(); i++) { + const Scope* scope = symbolDatabase->functionScopes[i]; + for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) { + if (tok->isName() && tok->varId() == 0 && tok->strAt(1) == "(") { + // alloca() is special as it depends on the code being C or C++, so it is not in Library + if (checkAlloca && Token::Match(tok, "alloca (") && (!tok->function() || tok->function()->nestedIn->type == Scope::eGlobal)) { + if (_tokenizer->isC()) + reportError(tok, Severity::warning, "allocaCalled", + "Obsolete function 'alloca' called. In C99 and later it is recommended to use a variable length array instead.\n" + "The obsolete function 'alloca' is called. In C99 and later it is recommended to use a variable length array or " + "a dynamically allocated array instead. The function 'alloca' is dangerous for many reasons " + "(http://stackoverflow.com/questions/1018853/why-is-alloca-not-considered-good-practice and http://linux.die.net/man/3/alloca)."); + else + reportError(tok, Severity::warning, "allocaCalled", + "Obsolete function 'alloca' called. In C++11 and later it is recommended to use std::array<> instead.\n" + "The obsolete function 'alloca' is called. In C++11 and later it is recommended to use std::array<> or " + "a dynamically allocated array instead. The function 'alloca' is dangerous for many reasons " + "(http://stackoverflow.com/questions/1018853/why-is-alloca-not-considered-good-practice and http://linux.die.net/man/3/alloca)."); + } else { + if (tok->function() && tok->function()->hasBody()) + continue; + + const Library::WarnInfo* wi = _settings->library.getWarnInfo(tok); + if (wi) { + if (_settings->isEnabled(Severity::toString(wi->severity)) && _settings->standards.c >= wi->standards.c && _settings->standards.cpp >= wi->standards.cpp) { + reportError(tok, wi->severity, tok->str() + "Called", wi->message); + } + } + } + } + } + } +} diff --git a/lib/checknonreentrantfunctions.h b/lib/checkfunctions.h similarity index 57% rename from lib/checknonreentrantfunctions.h rename to lib/checkfunctions.h index ee6173f4c..1a7e706c0 100644 --- a/lib/checknonreentrantfunctions.h +++ b/lib/checkfunctions.h @@ -16,55 +16,60 @@ * along with this program. If not, see . */ + //--------------------------------------------------------------------------- -#ifndef checknonreentrantfunctionsH -#define checknonreentrantfunctionsH +#ifndef checkfunctionsH +#define checkfunctionsH //--------------------------------------------------------------------------- #include "config.h" #include "check.h" #include -#include /// @addtogroup Checks /// @{ /** - * @brief Using non reentrant functions that can be replaced by their reentrant versions + * @brief Check for functions which should not be used */ -class CPPCHECKLIB CheckNonReentrantFunctions : public Check { +class CPPCHECKLIB CheckFunctions : public Check { public: - /** This constructor is used when registering the CheckNonReentrantFunctions */ - CheckNonReentrantFunctions() : Check(myName()) { + /** This constructor is used when registering the CheckFunctions */ + CheckFunctions() : Check(myName()) { } /** This constructor is used when running checks. */ - CheckNonReentrantFunctions(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) + CheckFunctions(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) : Check(myName(), tokenizer, settings, errorLogger) { } void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) { - CheckNonReentrantFunctions checkNonReentrantFunctions(tokenizer, settings, errorLogger); - checkNonReentrantFunctions.nonReentrantFunctions(); + CheckFunctions checkFunctions(tokenizer, settings, errorLogger); + checkFunctions.check(); } - /** Check for non reentrant functions */ - void nonReentrantFunctions(); + /** Check for functions that should not be used */ + void check(); private: + void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const { + CheckFunctions c(0, settings, errorLogger); - static std::string generateErrorMessage(const std::string& function); - - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const; - - static std::string myName() { - return "Non reentrant functions"; + for (std::map::const_iterator i = settings->library.functionwarn.cbegin(); i != settings->library.functionwarn.cend(); ++i) { + c.reportError(0, Severity::style, i->first+"Called", i->second.message); + } } - std::string classInfo() const; + static std::string myName() { + return "Check function usage"; + } + + std::string classInfo() const { + return "Warn if a function is called whose usage is discouraged\n"; + } }; /// @} //--------------------------------------------------------------------------- -#endif // checknonreentrantfunctionsH +#endif // checkfunctionsH diff --git a/lib/checknonreentrantfunctions.cpp b/lib/checknonreentrantfunctions.cpp deleted file mode 100644 index 8ae60fb08..000000000 --- a/lib/checknonreentrantfunctions.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2015 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 . - */ - -//--------------------------------------------------------------------------- -// Find non reentrant functions -//--------------------------------------------------------------------------- - -#include "checknonreentrantfunctions.h" -#include "symboldatabase.h" - -//--------------------------------------------------------------------------- - - -// Register this check class (by creating a static instance of it) -namespace { - CheckNonReentrantFunctions instance; -} - -namespace { - const std::set _nonReentrantFunctions = make_container< std::set > () - << "localtime" << "gmtime" << "strtok" << "gethostbyname" << "gethostbyaddr" << "getservbyname" - << "getservbyport" << "crypt" << "ttyname" << "gethostbyname2" - << "getprotobyname" << "getnetbyname" << "getnetbyaddr" << "getrpcbyname" << "getrpcbynumber" << "getrpcent" - << "ctermid" << "readdir" << "getlogin" << "getpwent" << "getpwnam" << "getpwuid" << "getspent" - << "fgetspent" << "getspnam" << "getgrnam" << "getgrgid" << "getnetgrent" << "tempnam" << "fgetpwent" - << "fgetgrent" << "ecvt" << "gcvt" << "getservent" << "gethostent" << "getgrent" << "fcvt" ; -} - -std::string CheckNonReentrantFunctions::generateErrorMessage(const std::string& function) -{ - return std::string("Non reentrant function '") + function + "' called. " + - "For threadsafe applications it is recommended to use the reentrant replacement function '" + function + "_r'."; -} - -void CheckNonReentrantFunctions::nonReentrantFunctions() -{ - if (!_settings->standards.posix || !_settings->isEnabled("portability")) - return; - - const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase(); - const std::size_t functions = symbolDatabase->functionScopes.size(); - for (std::size_t i = 0; i < functions; ++i) { - const Scope * scope = symbolDatabase->functionScopes[i]; - for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { - // Look for function invocations - if (tok->varId() != 0 || !tok->isName() || tok->strAt(1) != "(") - continue; - - // Check for non-reentrant function name - std::set::const_iterator it = _nonReentrantFunctions.find(tok->str()); - if (it == _nonReentrantFunctions.end()) - continue; - - const Token *prev = tok->previous(); - if (prev) { - // Ignore function definitions, class members or class definitions - if (prev->str() == ".") - continue; - - // Check for "std" or global namespace, ignore other namespaces - if (_tokenizer->isCPP() && prev->str() == "::" && prev->previous() && prev->previous()->str() != "std" && prev->previous()->isName()) - continue; - } - - // Only affecting multi threaded code, therefore this is "portability" - reportError(tok, Severity::portability, "nonreentrantFunctions" + *it, generateErrorMessage(*it)); - } - } -} -//--------------------------------------------------------------------------- - -void CheckNonReentrantFunctions::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const -{ - CheckNonReentrantFunctions c(0, settings, errorLogger); - - std::set::const_iterator it(_nonReentrantFunctions.begin()), itend(_nonReentrantFunctions.end()); - for (; it!=itend; ++it) { - c.reportError(0, Severity::portability, "nonreentrantFunctions"+*it, generateErrorMessage(*it)); - } -} - -std::string CheckNonReentrantFunctions::classInfo() const -{ - std::string info = "Warn if any of these non reentrant functions are used:\n"; - std::set::const_iterator it(_nonReentrantFunctions.begin()), itend(_nonReentrantFunctions.end()); - for (; it!=itend; ++it) { - info += "- " + *it + "\n"; - } - return info; -} diff --git a/lib/checkobsolescentfunctions.cpp b/lib/checkobsolescentfunctions.cpp deleted file mode 100644 index 27099f7a8..000000000 --- a/lib/checkobsolescentfunctions.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2015 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 . - */ - -//--------------------------------------------------------------------------- -// Obsolete functions -//--------------------------------------------------------------------------- - -#include "checkobsolescentfunctions.h" -#include "symboldatabase.h" - -//--------------------------------------------------------------------------- - -std::map CheckObsoleteFunctions::_obsoleteStandardFunctions; -std::map CheckObsoleteFunctions::_obsoletePosixFunctions; -std::map CheckObsoleteFunctions::_obsoleteC99Functions; - - -// Register this check class (by creating a static instance of it) -namespace { - CheckObsoleteFunctions instance; -} - -void CheckObsoleteFunctions::obsoleteFunctions() -{ - if (!_settings->isEnabled("style")) - return; - - const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); - const bool cStandard = _settings->standards.c >= Standards::C99 ; - - for (unsigned int i = 0; i < symbolDatabase->functionScopes.size(); i++) { - const Scope* scope = symbolDatabase->functionScopes[i]; - for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) { - if (tok->isName() && tok->varId()==0 && (!tok->function() || !tok->function()->hasBody()) && tok->strAt(1) == "(" && - tok->strAt(-1) != "." && (!Token::Match(tok->tokAt(-2), "%name% ::") || Token::simpleMatch(tok->tokAt(-2), "std ::"))) { - - std::map::const_iterator it = _obsoleteStandardFunctions.find(tok->str()); - if (it != _obsoleteStandardFunctions.end()) { - // If checking an old code base it might be uninteresting to update obsolete functions. - reportError(tok, Severity::style, "obsoleteFunctions"+it->first, it->second); - } else { - if (_settings->standards.posix) { - it = _obsoletePosixFunctions.find(tok->str()); - if (it != _obsoletePosixFunctions.end()) { - // If checking an old code base it might be uninteresting to update obsolete functions. - reportError(tok, Severity::style, "obsoleteFunctions"+it->first, it->second); - } - } - if (cStandard) { - // alloca : this function is obsolete in C but not in C++ (#4382) - it = _obsoleteC99Functions.find(tok->str()); - if (it != _obsoleteC99Functions.end() && !(tok->str() == "alloca" && _tokenizer->isCPP())) { - reportError(tok, Severity::style, "obsoleteFunctions"+it->first, it->second); - } - } - } - } - } - } -} -//--------------------------------------------------------------------------- diff --git a/lib/checkobsolescentfunctions.h b/lib/checkobsolescentfunctions.h deleted file mode 100644 index 3bc2d6fe0..000000000 --- a/lib/checkobsolescentfunctions.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2015 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 checkobsoletefunctionsH -#define checkobsoletefunctionsH -//--------------------------------------------------------------------------- - -#include "config.h" -#include "check.h" -#include -#include - - -/// @addtogroup Checks -/// @{ - -/** - * @brief Using obsolete functions that are always insecure to use. - */ - -class CPPCHECKLIB CheckObsoleteFunctions : public Check { -public: - /** This constructor is used when registering the CheckObsoleteFunctions */ - CheckObsoleteFunctions() : Check(myName()) { - initObsoleteFunctions(); - } - - /** This constructor is used when running checks. */ - CheckObsoleteFunctions(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) - : Check(myName(), tokenizer, settings, errorLogger) { - } - - void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) { - CheckObsoleteFunctions checkObsoleteFunctions(tokenizer, settings, errorLogger); - checkObsoleteFunctions.obsoleteFunctions(); - } - - /** Check for obsolete functions */ - void obsoleteFunctions(); - -private: - /* function name / error message */ - static std::map _obsoleteStandardFunctions; - static std::map _obsoletePosixFunctions; - static std::map _obsoleteC99Functions; - - /** init obsolete functions list ' */ - static void initObsoleteFunctions() { - // Obsolete posix functions, which messages suggest only one alternative and doesn't contain additional information. - const struct { - const char* bad; - const char* good; - } posix_stdmsgs[] = { - {"bsd_signal", "sigaction"}, - {"gethostbyaddr", "getnameinfo"}, - {"gethostbyname", "getaddrinfo"}, - {"bcmp", "memcmp"}, - {"bzero", "memset"}, - {"ecvt", "sprintf"}, - {"fcvt", "sprintf"}, - {"gcvt", "sprintf"}, - {"getwd", "getcwd"}, - {"index", "strchr"}, // See #2334 (using the Qt Model/View function 'index') - {"rindex", "strrchr"}, - {"pthread_attr_getstackaddr", "pthread_attr_getstack"}, - {"pthread_attr_setstackaddr", "pthread_attr_setstack"}, - {"vfork", "fork"}, - {"wcswcs", "wcsstr"}, - {"rand_r", "rand"}, - {"utime", "utimensat"}, - {"asctime_r", "strftime"}, - {"ctime_r", "strftime"} - }; - - for (std::size_t i = 0; i < (sizeof(posix_stdmsgs) / sizeof(*posix_stdmsgs)); ++i) { - _obsoletePosixFunctions[posix_stdmsgs[i].bad] = "Obsolete function '" + std::string(posix_stdmsgs[i].bad) + "' called. It is recommended to use the function '" + posix_stdmsgs[i].good + "' instead."; - } - - _obsoletePosixFunctions["usleep"] = "Obsolete function 'usleep' called. It is recommended to use the 'nanosleep' or 'setitimer' function instead.\n" - "The obsolete function 'usleep' is called. POSIX.1-2001 declares usleep() function obsolete and POSIX.1-2008 removes it. It is recommended that new applications use the 'nanosleep' or 'setitimer' function."; - - _obsoletePosixFunctions["bcopy"] = "Obsolete function 'bcopy' called. It is recommended to use the 'memmove' or 'memcpy' function instead."; - - _obsoletePosixFunctions["ftime"] = "Obsolete function 'ftime' called. It is recommended to use time(), gettimeofday() or clock_gettime() instead."; - - _obsoletePosixFunctions["getcontext"] = "Obsolete function 'getcontext' called. Due to portability issues, applications are recommended to be rewritten to use POSIX threads."; - _obsoletePosixFunctions["makecontext"] = "Obsolete function 'makecontext' called. Due to portability issues, applications are recommended to be rewritten to use POSIX threads."; - _obsoletePosixFunctions["swapcontext"] = "Obsolete function 'swapcontext' called. Due to portability issues, applications are recommended to be rewritten to use POSIX threads."; - - _obsoletePosixFunctions["scalbln"] = "Obsolete function 'scalb' called. It is recommended to use 'scalbln', 'scalblnf' or 'scalblnl' instead."; - - _obsoletePosixFunctions["ualarm"] = "Obsolete function 'ualarm' called. It is recommended to use 'timer_create', 'timer_delete', 'timer_getoverrun', 'timer_gettime' or 'timer_settime' instead."; - - _obsoletePosixFunctions["tmpnam"] = "Obsolete function 'tmpnam' called. It is recommended to use 'tmpfile', 'mkstemp' or 'mkdtemp' instead."; - - _obsoletePosixFunctions["tmpnam_r"] = "Obsolete function 'tmpnam_r' called. It is recommended to use 'tmpfile', 'mkstemp' or 'mkdtemp' instead."; - - _obsoleteStandardFunctions["gets"] = "Obsolete function 'gets' called. It is recommended to use the function 'fgets' instead.\n" - "The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun if the input data exceeds the size of the buffer. It is recommended to use the function 'fgets' instead."; - _obsoleteC99Functions["alloca"] = "Obsolete function 'alloca' called. In C99 and later it is recommended to use a variable length array instead.\n" - "The obsolete function 'alloca' is called. In C99 and later it is recommended to use a variable length array or a dynamically allocated array instead. The function 'alloca' is dangerous for many reasons (http://stackoverflow.com/questions/1018853/why-is-alloca-not-considered-good-practice and http://linux.die.net/man/3/alloca)."; - _obsoleteC99Functions["asctime"] = "Obsolete function 'asctime' called. It is recommended to use the function 'strftime' instead."; - // ctime is obsolete - it's not threadsafe. but there is no good replacement. - //_obsoleteC99Functions["ctime"] = "Obsolete function 'ctime' called. It is recommended to use the function 'strftime' instead."; - } - - void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const { - CheckObsoleteFunctions c(0, settings, errorLogger); - - for (std::map::const_iterator it = _obsoleteStandardFunctions.begin(); it != _obsoleteStandardFunctions.end(); ++it) - c.reportError(0, Severity::style, "obsoleteFunctions" + it->first, it->second); - for (std::map::const_iterator it = _obsoleteC99Functions.begin(); it != _obsoleteC99Functions.end(); ++it) - c.reportError(0, Severity::style, "obsoleteFunctions" + it->first, it->second); - for (std::map::const_iterator it = _obsoletePosixFunctions.begin(); it != _obsoletePosixFunctions.end(); ++it) - c.reportError(0, Severity::style, "obsoleteFunctions" + it->first, it->second); - } - - static std::string myName() { - return "Obsolete functions"; - } - - std::string classInfo() const { - std::string info = "Warn if any of these obsolete functions are used:\n"; - for (std::map::const_iterator it = _obsoleteStandardFunctions.begin(); it != _obsoleteStandardFunctions.end(); ++it) - info += "- " + it->first + "\n"; - for (std::map::const_iterator it = _obsoleteC99Functions.begin(); it != _obsoleteC99Functions.end(); ++it) - info += "- " + it->first + "\n"; - for (std::map::const_iterator it = _obsoletePosixFunctions.begin(); it != _obsoletePosixFunctions.end(); ++it) - info += "- " + it->first + "\n"; - return info; - } -}; -/// @} -//--------------------------------------------------------------------------- -#endif // checkobsoletefunctionsH diff --git a/lib/cppcheck.vcxproj b/lib/cppcheck.vcxproj index 12fa5ae88..d0980e948 100644 --- a/lib/cppcheck.vcxproj +++ b/lib/cppcheck.vcxproj @@ -55,15 +55,14 @@ + - - @@ -101,15 +100,14 @@ + - - diff --git a/lib/cppcheck.vcxproj.filters b/lib/cppcheck.vcxproj.filters index 5c8b9485b..c647ce900 100644 --- a/lib/cppcheck.vcxproj.filters +++ b/lib/cppcheck.vcxproj.filters @@ -32,15 +32,9 @@ Source Files - - Source Files - Source Files - - Source Files - Source Files @@ -143,6 +137,9 @@ Source Files + + Source Files + @@ -157,15 +154,9 @@ Header Files - - Header Files - Header Files - - Header Files - Header Files @@ -286,6 +277,9 @@ Header Files + + Header Files + diff --git a/lib/library.cpp b/lib/library.cpp index 2f79fd297..95e04efd3 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -621,6 +621,46 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co const tinyxml2::XMLAttribute* scan = functionnode->FindAttribute("scan"); const tinyxml2::XMLAttribute* secure = functionnode->FindAttribute("secure"); _formatstr[name] = std::make_pair(scan && scan->BoolValue(), secure && secure->BoolValue()); + } else if (functionnodename == "warn") { + WarnInfo wi; + const char* const severity = functionnode->Attribute("severity"); + if (severity == nullptr) + return Error(MISSING_ATTRIBUTE, "severity"); + wi.severity = Severity::fromString(severity); + + const char* const cstd = functionnode->Attribute("cstd"); + if (cstd) { + if (!wi.standards.setC(cstd)) + return Error(BAD_ATTRIBUTE_VALUE, cstd); + } else + wi.standards.c = Standards::C89; + + const char* const cppstd = functionnode->Attribute("cppstd"); + if (cppstd) { + if (!wi.standards.setCPP(cppstd)) + return Error(BAD_ATTRIBUTE_VALUE, cppstd); + } else + wi.standards.cpp = Standards::CPP03; + + const char* const reason = functionnode->Attribute("reason"); + const char* const alternatives = functionnode->Attribute("alternatives"); + if (reason && alternatives) { + // Construct message + wi.message = std::string(reason) + " function '" + name + "' called. It is recommended to use "; + std::vector alt = getnames(alternatives); + for (std::size_t i = 0; i < alt.size(); ++i) { + wi.message += "'" + alt[i] + "'"; + if (i == alt.size() - 1) + wi.message += " instead."; + else if (i == alt.size() - 2) + wi.message += " or "; + else + wi.message += ", "; + } + } else + wi.message = functionnode->GetText(); + + functionwarn[name] = wi; } else unknown_elements.insert(functionnodename); } @@ -852,6 +892,16 @@ bool Library::isNotLibraryFunction(const Token *ftok) const return args != callargs; } +const Library::WarnInfo* Library::getWarnInfo(const Token* ftok) const +{ + if (isNotLibraryFunction(ftok)) + return nullptr; + std::map::const_iterator i = functionwarn.find(functionName(ftok)); + if (i == functionwarn.cend()) + return nullptr; + return &i->second; +} + bool Library::isUseRetVal(const Token* ftok) const { return (!isNotLibraryFunction(ftok) && diff --git a/lib/library.h b/lib/library.h index 1e1f5c7ee..988ef2bd0 100644 --- a/lib/library.h +++ b/lib/library.h @@ -24,6 +24,8 @@ #include "config.h" #include "mathlib.h" #include "token.h" +#include "standards.h" +#include "errorlogger.h" #include #include @@ -120,6 +122,15 @@ public: std::set functionconst; std::set functionpure; + struct WarnInfo { + std::string message; + Standards standards; + Severity::SeverityType severity; + }; + std::map functionwarn; + + const WarnInfo* getWarnInfo(const Token* ftok) const; + // returns true if ftok is not a library function bool isNotLibraryFunction(const Token *ftok) const; diff --git a/lib/standards.h b/lib/standards.h index 0ecc4b215..b87cd704a 100644 --- a/lib/standards.h +++ b/lib/standards.h @@ -41,6 +41,33 @@ struct Standards { /** This constructor clear all the variables **/ Standards() : c(C11), cpp(CPP11), posix(false) {} + + bool setC(const std::string& str) { + if (str == "c89" || str == "C89") { + c = C89; + return true; + } + if (str == "c99" || str == "C99") { + c = C99; + return true; + } + if (str == "c11" || str == "C11") { + c = C11; + return true; + } + return false; + } + bool setCPP(const std::string& str) { + if (str == "c++03" || str == "C++03") { + cpp = CPP03; + return true; + } + if (str == "c++11" || str == "C++11") { + cpp = CPP11; + return true; + } + return false; + } }; /// @} diff --git a/test/testobsolescentfunctions.cpp b/test/testfunctions.cpp similarity index 50% rename from test/testobsolescentfunctions.cpp rename to test/testfunctions.cpp index f14ab07ba..81c2d99f4 100644 --- a/test/testobsolescentfunctions.cpp +++ b/test/testfunctions.cpp @@ -17,13 +17,13 @@ */ #include "tokenize.h" -#include "checkobsolescentfunctions.h" +#include "checkfunctions.h" #include "testsuite.h" -class TestObsoleteFunctions : public TestFixture { +class TestFunctions : public TestFixture { public: - TestObsoleteFunctions() : TestFixture("TestObsoleteFunctions") { + TestFunctions() : TestFixture("TestFunctions") { } private: @@ -31,8 +31,13 @@ private: void run() { settings.addEnabled("style"); + settings.addEnabled("warning"); + settings.addEnabled("portability"); settings.standards.posix = true; settings.standards.c = Standards::C11; + settings.standards.cpp = Standards::CPP11; + LOAD_LIB_2(settings.library, "std.cfg"); + LOAD_LIB_2(settings.library, "posix.cfg"); TEST_CASE(testbsd_signal); TEST_CASE(testgethostbyname); @@ -65,8 +70,9 @@ private: // function with body TEST_CASE(test_function_with_body); - // null pointer dereference in obsoleteFunctions - TEST_CASE(ticket3238); + // Non-reentrant functions + TEST_CASE(test_crypt); + TEST_CASE(test_namespace_handling); } void check(const char code[], const char filename[]="test.cpp") { @@ -79,9 +85,9 @@ private: tokenizer.tokenize(istr, filename); tokenizer.simplifyTokenList2(); - // Check for obsolete functions.. - CheckObsoleteFunctions checkObsoleteFunctions(&tokenizer, &settings, this); - checkObsoleteFunctions.obsoleteFunctions(); + // Check... + CheckFunctions checkFunctions(&tokenizer, &settings, this); + checkFunctions.check(); } void testbsd_signal() { @@ -89,7 +95,7 @@ private: "{\n" " bsd_signal(SIGABRT, SIG_IGN);\n" "}"); - ASSERT_EQUALS("[test.cpp:3]: (style) Obsolete function 'bsd_signal' called. It is recommended to use the function 'sigaction' instead.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (style) Obsolescent function 'bsd_signal' called. It is recommended to use 'sigaction' instead.\n", errout.str()); check("int f()\n" "{\n" @@ -108,7 +114,7 @@ private: " exit(1);\n" " }\n" "}"); - ASSERT_EQUALS("[test.cpp:4]: (style) Obsolete function 'gethostbyname' called. It is recommended to use the function 'getaddrinfo' instead.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (style) Obsolescent function 'gethostbyname' called. It is recommended to use 'getaddrinfo' instead.\n", errout.str()); } void testgethostbyaddr() { @@ -120,7 +126,7 @@ private: " exit(1);\n" " }\n" "}"); - ASSERT_EQUALS("[test.cpp:5]: (style) Obsolete function 'gethostbyaddr' called. It is recommended to use the function 'getnameinfo' instead.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:5]: (style) Obsolescent function 'gethostbyaddr' called. It is recommended to use 'getnameinfo' instead.\n", errout.str()); } void testusleep() { @@ -128,7 +134,7 @@ private: "{\n" " usleep( 1000 );\n" "}"); - ASSERT_EQUALS("[test.cpp:3]: (style) Obsolete function 'usleep' called. It is recommended to use the 'nanosleep' or 'setitimer' function instead.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (style) Obsolescent function 'usleep' called. It is recommended to use 'nanosleep' or 'setitimer' instead.\n", errout.str()); } void testindex() { @@ -168,7 +174,7 @@ private: " const char i = index(var, 0);\n" " return i;\n" "}"); - ASSERT_EQUALS("[test.cpp:4]: (style) Obsolete function 'index' called. It is recommended to use the function 'strchr' instead.\n", + ASSERT_EQUALS("[test.cpp:4]: (style) Obsolescent function 'index' called. It is recommended to use 'strchr' instead.\n", errout.str()); } @@ -176,7 +182,7 @@ private: check("void TDataModel::forceRowRefresh(int row) {\n" " emit dataChanged(index(row, 0), index(row, columnCount() - 1));\n" "}"); - ASSERT_EQUALS("[test.cpp:2]: (style) Obsolete function 'index' called. It is recommended to use the function 'strchr' instead.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:2]: (style) Obsolescent function 'index' called. It is recommended to use 'strchr' instead.\n", errout.str()); } void testrindex() { @@ -191,7 +197,7 @@ private: " const char var[7] = \"rindex\";\n" " print(rindex(var, 0));\n" "}"); - ASSERT_EQUALS("[test.cpp:4]: (style) Obsolete function 'rindex' called. It is recommended to use the function 'strrchr' instead.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (style) Obsolescent function 'rindex' called. It is recommended to use 'strrchr' instead.\n", errout.str()); } @@ -207,29 +213,45 @@ private: void testgets() { check("void f()\n" "{\n" - " char *x = gets();\n" + " char *x = gets(a);\n" "}"); - ASSERT_EQUALS("[test.cpp:3]: (style) Obsolete function 'gets' called. It is recommended to use the function 'fgets' instead.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (warning) Obsolete function 'gets' called. It is recommended to use 'fgets' instead.\n", errout.str()); check("void f()\n" "{\n" - " foo(x, gets());\n" + " foo(x, gets(a));\n" "}"); - ASSERT_EQUALS("[test.cpp:3]: (style) Obsolete function 'gets' called. It is recommended to use the function 'fgets' instead.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (warning) Obsolete function 'gets' called. It is recommended to use 'fgets' instead.\n", errout.str()); } void testalloca() { check("void f()\n" "{\n" " char *x = alloca(10);\n" - "}\n", "test.cpp"); // #4382 - there are no VLAs in C++ + "}", "test.cpp"); // #4382 - there are no VLAs in C++ + ASSERT_EQUALS("[test.cpp:3]: (warning) Obsolete function 'alloca' called. In C++11 and later it is recommended to use std::array<> instead.\n", errout.str()); + + check("void f()\n" + "{\n" + " char *x = alloca(10);\n" + "}", "test.c"); + ASSERT_EQUALS("[test.c:3]: (warning) Obsolete function 'alloca' called. In C99 and later it is recommended to use a variable length array instead.\n", errout.str()); + + settings.standards.c = Standards::C89; + settings.standards.cpp = Standards::CPP03; + check("void f()\n" + "{\n" + " char *x = alloca(10);\n" + "}", "test.cpp"); // #4382 - there are no VLAs in C++ ASSERT_EQUALS("", errout.str()); check("void f()\n" "{\n" " char *x = alloca(10);\n" - "}\n", "test.c"); - ASSERT_EQUALS("[test.c:3]: (style) Obsolete function 'alloca' called. In C99 and later it is recommended to use a variable length array instead.\n", errout.str()); + "}", "test.c"); + ASSERT_EQUALS("", errout.str()); + settings.standards.c = Standards::C11; + settings.standards.cpp = Standards::CPP11; } // ticket #3121 @@ -253,8 +275,8 @@ private: " char *x = std::gets(str);\n" " char *y = gets(str);\n" "}"); - ASSERT_EQUALS("[test.cpp:3]: (style) Obsolete function 'gets' called. It is recommended to use the function 'fgets' instead.\n" - "[test.cpp:4]: (style) Obsolete function 'gets' called. It is recommended to use the function 'fgets' instead.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (warning) Obsolete function 'gets' called. It is recommended to use 'fgets' instead.\n" + "[test.cpp:4]: (warning) Obsolete function 'gets' called. It is recommended to use 'fgets' instead.\n", errout.str()); } // multiple use @@ -264,8 +286,8 @@ private: " char *x = std::gets(str);\n" " usleep( 1000 );\n" "}"); - ASSERT_EQUALS("[test.cpp:3]: (style) Obsolete function 'gets' called. It is recommended to use the function 'fgets' instead.\n" - "[test.cpp:4]: (style) Obsolete function 'usleep' called. It is recommended to use the 'nanosleep' or 'setitimer' function instead.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (warning) Obsolete function 'gets' called. It is recommended to use 'fgets' instead.\n" + "[test.cpp:4]: (style) Obsolescent function 'usleep' called. It is recommended to use 'nanosleep' or 'setitimer' instead.\n", errout.str()); } void test_c_declaration() { @@ -275,14 +297,14 @@ private: " char s [ 10 ] ;\n" " gets ( s ) ;\n" "}"); - ASSERT_EQUALS("[test.cpp:5]: (style) Obsolete function 'gets' called. It is recommended to use the function 'fgets' instead.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:5]: (warning) Obsolete function 'gets' called. It is recommended to use 'fgets' instead.\n", errout.str()); check("int getcontext(ucontext_t *ucp);\n" "int f (ucontext_t *ucp)\n" "{\n" " getcontext ( ucp ) ;\n" "}"); - ASSERT_EQUALS("[test.cpp:4]: (style) Obsolete function 'getcontext' called. Due to portability issues, applications are recommended to be rewritten to use POSIX threads.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (portability) Obsolescent function 'getcontext' called. Applications are recommended to be rewritten to use POSIX threads.\n", errout.str()); } void test_function_with_body() { @@ -295,11 +317,81 @@ private: ASSERT_EQUALS("", errout.str()); } - void ticket3238() { - check("__FBSDID(\"...\");\n"); + void test_crypt() { + check("void f(char *pwd)\n" + "{\n" + " char *cpwd;" + " crypt(pwd, cpwd);\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'crypt' called. For threadsafe applications it is recommended to use the reentrant replacement function 'crypt_r'.\n", errout.str()); + + check("void f()\n" + "{\n" + " char *pwd = getpass(\"Password:\");" + " char *cpwd;" + " crypt(pwd, cpwd);\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'crypt' called. For threadsafe applications it is recommended to use the reentrant replacement function 'crypt_r'.\n", errout.str()); + + check("int f()\n" + "{\n" + " int crypt = 0;" + " return crypt;\n" + "}"); ASSERT_EQUALS("", errout.str()); } + void test_namespace_handling() { + check("int f()\n" + "{\n" + " time_t t = 0;" + " std::localtime(&t);\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'localtime' called. For threadsafe applications it is recommended to use the reentrant replacement function 'localtime_r'.\n", errout.str()); + + // Passed as function argument + check("int f()\n" + "{\n" + " printf(\"Magic guess: %d\n\", getpwent());\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'getpwent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getpwent_r'.\n", errout.str()); + + // Pass return value + check("int f()\n" + "{\n" + " time_t t = 0;" + " struct tm *foo = localtime(&t);\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'localtime' called. For threadsafe applications it is recommended to use the reentrant replacement function 'localtime_r'.\n", errout.str()); + + // Access via global namespace + check("int f()\n" + "{\n" + " ::getpwent();\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'getpwent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getpwent_r'.\n", errout.str()); + + // Be quiet on function definitions + check("int getpwent()\n" + "{\n" + " return 123;\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + // Be quiet on other namespaces + check("int f()\n" + "{\n" + " foobar::getpwent();\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + // Be quiet on class member functions + check("int f()\n" + "{\n" + " foobar.getpwent();\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } }; -REGISTER_TEST(TestObsoleteFunctions) +REGISTER_TEST(TestFunctions) diff --git a/test/testgarbage.cpp b/test/testgarbage.cpp index aa3b366af..9d6c6413f 100644 --- a/test/testgarbage.cpp +++ b/test/testgarbage.cpp @@ -206,6 +206,7 @@ private: TEST_CASE(garbageCode155); // #7118 TEST_CASE(garbageCode156); // #7120 TEST_CASE(garbageCode157); // #7131 + TEST_CASE(garbageCode158); // #3238 TEST_CASE(garbageValueFlow); TEST_CASE(garbageSymbolDatabase); @@ -1241,6 +1242,11 @@ private: "template std::swap\n"), InternalError); } + void garbageCode158() { // #3238 + checkCode("__FBSDID(\"...\");\n"); + } + + void garbageValueFlow() { // #6089 const char* code = "{} int foo(struct, x1, struct x2, x3, int, x5, x6, x7)\n" diff --git a/test/testlibrary.cpp b/test/testlibrary.cpp index 45e3b8f7f..f259b7dd4 100644 --- a/test/testlibrary.cpp +++ b/test/testlibrary.cpp @@ -40,6 +40,7 @@ private: TEST_CASE(function_arg_valid); TEST_CASE(function_arg_minsize); TEST_CASE(function_namespace); + TEST_CASE(function_warn); TEST_CASE(memory); TEST_CASE(memory2); // define extra "free" allocation functions TEST_CASE(resource); @@ -305,6 +306,42 @@ private: } } + void function_warn() const { + const char xmldata[] = "\n" + "\n" + " \n" + " Message\n" + " \n" + " \n" + " \n" + " \n" + ""; + + Library library; + readLibrary(library, xmldata); + + TokenList tokenList(nullptr); + std::istringstream istr("a(); b();"); + tokenList.createTokens(istr); + + const Library::WarnInfo* a = library.getWarnInfo(tokenList.front()); + const Library::WarnInfo* b = library.getWarnInfo(tokenList.front()->tokAt(4)); + + ASSERT_EQUALS(2, library.functionwarn.size()); + ASSERT(a && b); + if (a && b) { + ASSERT_EQUALS("Message", a->message); + ASSERT_EQUALS(Severity::style, a->severity); + ASSERT_EQUALS(Standards::C99, a->standards.c); + ASSERT_EQUALS(Standards::CPP03, a->standards.cpp); + + ASSERT_EQUALS("Obsolescent function 'b' called. It is recommended to use 'c', 'd' or 'e' instead.", b->message); + ASSERT_EQUALS(Severity::performance, b->severity); + ASSERT_EQUALS(Standards::C89, b->standards.c); + ASSERT_EQUALS(Standards::CPP11, b->standards.cpp); + } + } + void memory() const { const char xmldata[] = "\n" "\n" diff --git a/test/testnonreentrantfunctions.cpp b/test/testnonreentrantfunctions.cpp deleted file mode 100644 index d7edc7be7..000000000 --- a/test/testnonreentrantfunctions.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2015 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 "tokenize.h" -#include "checknonreentrantfunctions.h" -#include "testsuite.h" - - -class TestNonReentrantFunctions : public TestFixture { -public: - TestNonReentrantFunctions() : TestFixture("TestNonReentrantFunctions") { - } - -private: - Settings settings; - - void run() { - settings.standards.posix = true; - settings.addEnabled("portability"); - - TEST_CASE(test_crypt); - TEST_CASE(test_namespace_handling); - } - - void check(const char code[]) { - // Clear the error buffer.. - errout.str(""); - - // Tokenize.. - Tokenizer tokenizer(&settings, this); - std::istringstream istr(code); - tokenizer.tokenize(istr, "test.cpp"); - tokenizer.simplifyTokenList2(); - - // Check for non reentrant functions.. - CheckNonReentrantFunctions checkNonReentrantFunctions(&tokenizer, &settings, this); - checkNonReentrantFunctions.nonReentrantFunctions(); - } - - void test_crypt() { - check("void f(char *pwd)\n" - "{\n" - " char *cpwd;" - " crypt(pwd, cpwd);\n" - "}"); - ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'crypt' called. For threadsafe applications it is recommended to use the reentrant replacement function 'crypt_r'.\n", errout.str()); - - check("void f()\n" - "{\n" - " char *pwd = getpass(\"Password:\");" - " char *cpwd;" - " crypt(pwd, cpwd);\n" - "}"); - ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'crypt' called. For threadsafe applications it is recommended to use the reentrant replacement function 'crypt_r'.\n", errout.str()); - - check("int f()\n" - "{\n" - " int crypt = 0;" - " return crypt;\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - - void test_namespace_handling() { - check("int f()\n" - "{\n" - " time_t t = 0;" - " std::localtime(&t);\n" - "}"); - ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'localtime' called. For threadsafe applications it is recommended to use the reentrant replacement function 'localtime_r'.\n", errout.str()); - - // Passed as function argument - check("int f()\n" - "{\n" - " printf(\"Magic guess: %d\n\", getpwent());\n" - "}"); - ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'getpwent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getpwent_r'.\n", errout.str()); - - // Pass return value - check("int f()\n" - "{\n" - " time_t t = 0;" - " struct tm *foo = localtime(&t);\n" - "}"); - ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'localtime' called. For threadsafe applications it is recommended to use the reentrant replacement function 'localtime_r'.\n", errout.str()); - - // Access via global namespace - check("int f()\n" - "{\n" - " ::getpwent();\n" - "}"); - ASSERT_EQUALS("[test.cpp:3]: (portability) Non reentrant function 'getpwent' called. For threadsafe applications it is recommended to use the reentrant replacement function 'getpwent_r'.\n", errout.str()); - - // Be quiet on function definitions - check("int getpwent()\n" - "{\n" - " return 123;\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - // Be quiet on other namespaces - check("int f()\n" - "{\n" - " foobar::getpwent();\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - // Be quiet on class member functions - check("int f()\n" - "{\n" - " foobar.getpwent();\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } -}; - -REGISTER_TEST(TestNonReentrantFunctions) diff --git a/test/testrunner.vcxproj b/test/testrunner.vcxproj index 32a9accd7..966831702 100644 --- a/test/testrunner.vcxproj +++ b/test/testrunner.vcxproj @@ -53,9 +53,8 @@ - - + diff --git a/test/testrunner.vcxproj.filters b/test/testrunner.vcxproj.filters index 81846d301..e00e47f20 100644 --- a/test/testrunner.vcxproj.filters +++ b/test/testrunner.vcxproj.filters @@ -64,15 +64,9 @@ Source Files - - Source Files - Source Files - - Source Files - Source Files @@ -205,6 +199,9 @@ Source Files + + Source Files +