2010-04-13 19:25:08 +02:00
|
|
|
/*
|
|
|
|
* Cppcheck - A tool for static C/C++ code analysis
|
2018-01-14 15:37:52 +01:00
|
|
|
* Copyright (C) 2007-2018 Cppcheck team.
|
2010-04-13 19:25:08 +02:00
|
|
|
*
|
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#include "cppcheck.h"
|
|
|
|
|
|
|
|
#include "check.h"
|
2016-10-29 12:18:11 +02:00
|
|
|
#include "checkunusedfunctions.h"
|
2017-05-27 04:33:47 +02:00
|
|
|
#include "library.h"
|
|
|
|
#include "mathlib.h"
|
|
|
|
#include "path.h"
|
|
|
|
#include "platform.h"
|
|
|
|
#include "preprocessor.h" // Preprocessor
|
|
|
|
#include "suppressions.h"
|
2017-03-30 10:14:17 +02:00
|
|
|
#include "timer.h"
|
2017-05-27 04:33:47 +02:00
|
|
|
#include "token.h"
|
|
|
|
#include "tokenize.h" // Tokenizer
|
|
|
|
#include "tokenlist.h"
|
2017-03-30 10:14:17 +02:00
|
|
|
#include "version.h"
|
2016-10-29 12:18:11 +02:00
|
|
|
|
2017-05-18 22:25:49 +02:00
|
|
|
#include <simplecpp.h>
|
2017-05-27 04:33:47 +02:00
|
|
|
#include <tinyxml2.h>
|
2010-04-13 19:25:08 +02:00
|
|
|
#include <algorithm>
|
2017-05-27 04:33:47 +02:00
|
|
|
#include <cstring>
|
|
|
|
#include <new>
|
|
|
|
#include <set>
|
2010-09-06 21:00:56 +02:00
|
|
|
#include <stdexcept>
|
2017-05-27 04:33:47 +02:00
|
|
|
#include <vector>
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2011-02-14 19:37:58 +01:00
|
|
|
#ifdef HAVE_RULES
|
2010-12-12 11:56:22 +01:00
|
|
|
#define PCRE_STATIC
|
|
|
|
#include <pcre.h>
|
2010-12-31 10:24:51 +01:00
|
|
|
#endif
|
2010-12-12 11:56:22 +01:00
|
|
|
|
2014-01-04 10:41:13 +01:00
|
|
|
static const char Version[] = CPPCHECK_VERSION_STRING;
|
2011-08-11 16:34:59 +02:00
|
|
|
static const char ExtraVersion[] = "";
|
|
|
|
|
2010-04-13 19:25:08 +02:00
|
|
|
static TimerResults S_timerResults;
|
|
|
|
|
Mapped toomanyconfigs ,AssignmentAddressToInteger
,AssignmentIntegerToAddress ,CastIntegerToAddressAtReturn
,CastAddressToIntegerAtReturn ,assertWithSideEffect ,assignmentInAssert
,uselessAssignmentArg ,uselessAssignmentPtrArg
,comparisonOfFuncReturningBoolError
,comparisonOfTwoFuncsReturningBoolError ,comparisonOfBoolWithBoolError
,incrementboolean ,comparisonOfBoolWithInt ,compareBoolExpressionWithInt
,negativeIndex ,pointerOutOfBounds ,arrayIndexThenCheck
,possibleBufferAccessOutOfBounds ,argumentSize
,arrayIndexOutOfBoundsCond ,noConstructor ,copyCtorPointerCopying
,noCopyConstructor ,uninitMemberVar ,operatorEqVarError
,unusedPrivateFunction ,memsetClassFloat ,mallocOnClassWarning
,operatorEq ,thisSubtraction ,operatorEqRetRefThis ,operatorEqToSelf
,useInitializationList ,duplInheritedMember ,assignIfError
,comparisonError ,multiCondition ,mismatchingBitAnd
,oppositeInnerCondition ,incorrectLogicOperator ,redundantCondition
,moduloAlwaysTrueFalse to their CWEs ids.
2016-02-20 23:56:36 +01:00
|
|
|
// CWE ids used
|
|
|
|
static const CWE CWE398(398U); // Indicator of Poor Code Quality
|
|
|
|
|
2011-02-16 02:12:15 +01:00
|
|
|
CppCheck::CppCheck(ErrorLogger &errorLogger, bool useGlobalSuppressions)
|
2018-06-17 19:20:07 +02:00
|
|
|
: mErrorLogger(errorLogger), mExitCode(0), mUseGlobalSuppressions(useGlobalSuppressions), mTooManyConfigs(false), mSimplify(true)
|
2010-04-13 19:25:08 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CppCheck::~CppCheck()
|
|
|
|
{
|
2018-06-17 07:36:05 +02:00
|
|
|
while (!mFileInfo.empty()) {
|
2018-06-17 07:40:13 +02:00
|
|
|
delete mFileInfo.back();
|
|
|
|
mFileInfo.pop_back();
|
2014-11-15 10:43:49 +01:00
|
|
|
}
|
2018-06-16 16:10:28 +02:00
|
|
|
S_timerResults.ShowResults(mSettings.showtime);
|
2010-04-13 19:25:08 +02:00
|
|
|
}
|
|
|
|
|
2011-04-24 18:10:25 +02:00
|
|
|
const char * CppCheck::version()
|
2010-04-13 19:25:08 +02:00
|
|
|
{
|
2011-08-11 16:34:59 +02:00
|
|
|
return Version;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char * CppCheck::extraVersion()
|
|
|
|
{
|
|
|
|
return ExtraVersion;
|
2010-04-13 19:25:08 +02:00
|
|
|
}
|
|
|
|
|
2011-04-24 18:10:25 +02:00
|
|
|
unsigned int CppCheck::check(const std::string &path)
|
2010-04-13 19:25:08 +02:00
|
|
|
{
|
2018-04-11 09:50:42 +02:00
|
|
|
std::ifstream fin(path);
|
2018-04-21 13:28:26 +02:00
|
|
|
return checkFile(Path::simplifyPath(path), emptyString, fin);
|
2010-04-13 19:25:08 +02:00
|
|
|
}
|
|
|
|
|
2011-04-24 18:10:25 +02:00
|
|
|
unsigned int CppCheck::check(const std::string &path, const std::string &content)
|
2010-04-13 19:25:08 +02:00
|
|
|
{
|
2014-10-03 10:40:48 +02:00
|
|
|
std::istringstream iss(content);
|
2018-04-21 13:28:26 +02:00
|
|
|
return checkFile(Path::simplifyPath(path), emptyString, iss);
|
2010-04-13 19:25:08 +02:00
|
|
|
}
|
|
|
|
|
2016-08-13 10:50:03 +02:00
|
|
|
unsigned int CppCheck::check(const ImportProject::FileSettings &fs)
|
|
|
|
{
|
2018-06-17 07:29:07 +02:00
|
|
|
CppCheck temp(mErrorLogger, mUseGlobalSuppressions);
|
2018-06-16 16:10:28 +02:00
|
|
|
temp.mSettings = mSettings;
|
|
|
|
if (!temp.mSettings.userDefines.empty())
|
|
|
|
temp.mSettings.userDefines += ';';
|
|
|
|
temp.mSettings.userDefines += fs.cppcheckDefines();
|
|
|
|
temp.mSettings.includePaths = fs.includePaths;
|
|
|
|
// TODO: temp.mSettings.userUndefs = fs.undefs;
|
2016-08-13 10:50:03 +02:00
|
|
|
if (fs.platformType != Settings::Unspecified) {
|
2018-06-16 16:10:28 +02:00
|
|
|
temp.mSettings.platform(fs.platformType);
|
2016-08-13 10:50:03 +02:00
|
|
|
}
|
2018-04-11 09:50:42 +02:00
|
|
|
std::ifstream fin(fs.filename);
|
2018-04-21 13:28:26 +02:00
|
|
|
return temp.checkFile(Path::simplifyPath(fs.filename), fs.cfg, fin);
|
2016-08-13 10:50:03 +02:00
|
|
|
}
|
|
|
|
|
2018-04-21 13:28:26 +02:00
|
|
|
unsigned int CppCheck::checkFile(const std::string& filename, const std::string &cfgname, std::istream& fileStream)
|
2010-04-13 19:25:08 +02:00
|
|
|
{
|
2018-06-17 07:43:25 +02:00
|
|
|
mExitCode = 0;
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2012-10-03 19:51:09 +02:00
|
|
|
// only show debug warnings for accepted C/C++ source files
|
2013-10-31 19:09:01 +01:00
|
|
|
if (!Path::acceptFile(filename))
|
2018-06-16 16:10:28 +02:00
|
|
|
mSettings.debugwarnings = false;
|
2012-01-06 16:08:08 +01:00
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.terminated())
|
2018-06-17 07:43:25 +02:00
|
|
|
return mExitCode;
|
2011-04-24 18:10:25 +02:00
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
if (!mSettings.quiet) {
|
2014-04-02 13:56:34 +02:00
|
|
|
std::string fixedpath = Path::simplifyPath(filename);
|
2011-04-24 18:10:25 +02:00
|
|
|
fixedpath = Path::toNativeSeparators(fixedpath);
|
2018-06-16 16:10:28 +02:00
|
|
|
mErrorLogger.reportOut(std::string("Checking ") + fixedpath + ' ' + cfgname + std::string("..."));
|
2016-08-13 10:50:03 +02:00
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.verbose) {
|
|
|
|
mErrorLogger.reportOut("Defines: " + mSettings.userDefines);
|
2016-08-13 10:50:03 +02:00
|
|
|
std::string includePaths;
|
2018-06-16 16:10:28 +02:00
|
|
|
for (const std::string &I : mSettings.includePaths)
|
2018-05-22 23:22:46 +02:00
|
|
|
includePaths += " -I" + I;
|
2018-06-16 16:10:28 +02:00
|
|
|
mErrorLogger.reportOut("Includes:" + includePaths);
|
|
|
|
mErrorLogger.reportOut(std::string("Platform:") + mSettings.platformString());
|
2016-08-13 10:50:03 +02:00
|
|
|
}
|
2011-04-24 18:10:25 +02:00
|
|
|
}
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2017-05-16 14:07:23 +02:00
|
|
|
if (plistFile.is_open()) {
|
|
|
|
plistFile << ErrorLogger::plistFooter();
|
|
|
|
plistFile.close();
|
|
|
|
}
|
|
|
|
|
2017-08-09 20:00:26 +02:00
|
|
|
CheckUnusedFunctions checkUnusedFunctions(nullptr, nullptr, nullptr);
|
2016-11-07 21:49:58 +01:00
|
|
|
|
2015-05-25 21:15:55 +02:00
|
|
|
bool internalErrorFound(false);
|
2011-10-13 20:53:06 +02:00
|
|
|
try {
|
2018-06-16 16:10:28 +02:00
|
|
|
Preprocessor preprocessor(mSettings, this);
|
2016-07-20 12:21:00 +02:00
|
|
|
std::set<std::string> configurations;
|
|
|
|
|
|
|
|
simplecpp::OutputList outputList;
|
|
|
|
std::vector<std::string> files;
|
2016-07-21 07:48:17 +02:00
|
|
|
simplecpp::TokenList tokens1(fileStream, files, filename, &outputList);
|
2017-05-28 20:34:58 +02:00
|
|
|
|
|
|
|
// If there is a syntax error, report it and stop
|
|
|
|
for (simplecpp::OutputList::const_iterator it = outputList.begin(); it != outputList.end(); ++it) {
|
2017-09-12 22:42:10 +02:00
|
|
|
bool err;
|
|
|
|
switch (it->type) {
|
|
|
|
case simplecpp::Output::ERROR:
|
|
|
|
case simplecpp::Output::INCLUDE_NESTED_TOO_DEEPLY:
|
|
|
|
case simplecpp::Output::SYNTAX_ERROR:
|
|
|
|
case simplecpp::Output::UNHANDLED_CHAR_ERROR:
|
|
|
|
err = true;
|
|
|
|
break;
|
|
|
|
case simplecpp::Output::WARNING:
|
|
|
|
case simplecpp::Output::MISSING_HEADER:
|
|
|
|
case simplecpp::Output::PORTABILITY_BACKSLASH:
|
|
|
|
err = false;
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
const ErrorLogger::ErrorMessage::FileLocation loc1(it->location.file(), it->location.line);
|
2018-04-09 09:54:39 +02:00
|
|
|
std::list<ErrorLogger::ErrorMessage::FileLocation> callstack(1, loc1);
|
2017-09-12 22:42:10 +02:00
|
|
|
|
|
|
|
ErrorLogger::ErrorMessage errmsg(callstack,
|
|
|
|
"",
|
|
|
|
Severity::error,
|
|
|
|
it->msg,
|
|
|
|
"syntaxError",
|
|
|
|
false);
|
2018-06-16 16:10:28 +02:00
|
|
|
mErrorLogger.reportErr(errmsg);
|
2017-09-12 22:42:10 +02:00
|
|
|
return 1;
|
|
|
|
}
|
2017-05-28 20:34:58 +02:00
|
|
|
}
|
|
|
|
|
2016-07-21 07:48:17 +02:00
|
|
|
preprocessor.loadFiles(tokens1, files);
|
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
if (!mSettings.plistOutput.empty()) {
|
2017-05-16 14:07:23 +02:00
|
|
|
std::string filename2;
|
2017-05-27 04:15:54 +02:00
|
|
|
if (filename.find('/') != std::string::npos)
|
|
|
|
filename2 = filename.substr(filename.rfind('/') + 1);
|
2017-05-16 14:07:23 +02:00
|
|
|
else
|
|
|
|
filename2 = filename;
|
2018-06-16 16:10:28 +02:00
|
|
|
filename2 = mSettings.plistOutput + filename2.substr(0, filename2.find('.')) + ".plist";
|
2017-05-16 14:07:23 +02:00
|
|
|
plistFile.open(filename2);
|
|
|
|
plistFile << ErrorLogger::plistHeader(version(), files);
|
|
|
|
}
|
|
|
|
|
2017-04-14 10:46:35 +02:00
|
|
|
// write dump file xml prolog
|
|
|
|
std::ofstream fdump;
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.dump) {
|
|
|
|
const std::string dumpfile(mSettings.dumpFile.empty() ? (filename + ".dump") : mSettings.dumpFile);
|
2018-04-11 09:50:42 +02:00
|
|
|
fdump.open(dumpfile);
|
2017-04-14 10:46:35 +02:00
|
|
|
if (fdump.is_open()) {
|
|
|
|
fdump << "<?xml version=\"1.0\"?>" << std::endl;
|
|
|
|
fdump << "<dumps>" << std::endl;
|
2017-04-15 12:25:44 +02:00
|
|
|
fdump << " <platform"
|
2018-06-16 16:10:28 +02:00
|
|
|
<< " name=\"" << mSettings.platformString() << '\"'
|
|
|
|
<< " char_bit=\"" << mSettings.char_bit << '\"'
|
|
|
|
<< " short_bit=\"" << mSettings.short_bit << '\"'
|
|
|
|
<< " int_bit=\"" << mSettings.int_bit << '\"'
|
|
|
|
<< " long_bit=\"" << mSettings.long_bit << '\"'
|
|
|
|
<< " long_long_bit=\"" << mSettings.long_long_bit << '\"'
|
|
|
|
<< " pointer_bit=\"" << (mSettings.sizeof_pointer * mSettings.char_bit) << '\"'
|
2017-04-15 12:25:44 +02:00
|
|
|
<< "/>\n";
|
2017-04-14 10:46:35 +02:00
|
|
|
fdump << " <rawtokens>" << std::endl;
|
|
|
|
for (unsigned int i = 0; i < files.size(); ++i)
|
|
|
|
fdump << " <file index=\"" << i << "\" name=\"" << ErrorLogger::toxml(files[i]) << "\"/>" << std::endl;
|
|
|
|
for (const simplecpp::Token *tok = tokens1.cfront(); tok; tok = tok->next) {
|
|
|
|
fdump << " <tok "
|
|
|
|
<< "fileIndex=\"" << tok->location.fileIndex << "\" "
|
|
|
|
<< "linenr=\"" << tok->location.line << "\" "
|
2018-05-14 13:00:22 +02:00
|
|
|
<< "str=\"" << ErrorLogger::toxml(tok->str()) << "\""
|
2017-04-14 10:46:35 +02:00
|
|
|
<< "/>" << std::endl;
|
|
|
|
}
|
|
|
|
fdump << " </rawtokens>" << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-21 07:48:17 +02:00
|
|
|
// Parse comments and then remove them
|
|
|
|
preprocessor.inlineSuppressions(tokens1);
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.dump && fdump.is_open()) {
|
|
|
|
mSettings.nomsg.dump(fdump);
|
2018-04-24 22:19:24 +02:00
|
|
|
}
|
2016-07-21 07:48:17 +02:00
|
|
|
tokens1.removeComments();
|
|
|
|
preprocessor.removeComments();
|
2016-07-20 12:21:00 +02:00
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
if (!mSettings.buildDir.empty()) {
|
2016-10-29 22:40:44 +02:00
|
|
|
// Get toolinfo
|
2018-08-09 09:26:54 +02:00
|
|
|
std::ostringstream toolinfo;
|
|
|
|
toolinfo << CPPCHECK_VERSION_STRING;
|
|
|
|
toolinfo << (mSettings.isEnabled(Settings::WARNING) ? 'w' : ' ');
|
|
|
|
toolinfo << (mSettings.isEnabled(Settings::STYLE) ? 's' : ' ');
|
|
|
|
toolinfo << (mSettings.isEnabled(Settings::PERFORMANCE) ? 'p' : ' ');
|
|
|
|
toolinfo << (mSettings.isEnabled(Settings::PORTABILITY) ? 'p' : ' ');
|
|
|
|
toolinfo << (mSettings.isEnabled(Settings::INFORMATION) ? 'i' : ' ');
|
|
|
|
toolinfo << mSettings.userDefines;
|
|
|
|
mSettings.nomsg.dump(toolinfo);
|
2016-10-29 22:40:44 +02:00
|
|
|
|
|
|
|
// Calculate checksum so it can be compared with old checksum / future checksums
|
2018-08-09 09:26:54 +02:00
|
|
|
const unsigned int checksum = preprocessor.calculateChecksum(tokens1, toolinfo.str());
|
2016-10-29 12:18:11 +02:00
|
|
|
std::list<ErrorLogger::ErrorMessage> errors;
|
2018-06-17 07:31:34 +02:00
|
|
|
if (!mAnalyzerInformation.analyzeFile(mSettings.buildDir, filename, cfgname, checksum, &errors)) {
|
2016-10-29 12:18:11 +02:00
|
|
|
while (!errors.empty()) {
|
|
|
|
reportErr(errors.front());
|
|
|
|
errors.pop_front();
|
|
|
|
}
|
2018-06-17 07:43:25 +02:00
|
|
|
return mExitCode; // known results => no need to reanalyze file
|
2016-10-29 12:18:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-24 14:02:21 +02:00
|
|
|
// Get directives
|
|
|
|
preprocessor.setDirectives(tokens1);
|
2017-05-17 21:58:46 +02:00
|
|
|
preprocessor.simplifyPragmaAsm(&tokens1);
|
2016-07-24 14:02:21 +02:00
|
|
|
|
2016-07-25 14:52:23 +02:00
|
|
|
preprocessor.setPlatformInfo(&tokens1);
|
|
|
|
|
2016-07-20 12:21:00 +02:00
|
|
|
// Get configurations..
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.userDefines.empty() || mSettings.force) {
|
|
|
|
Timer t("Preprocessor::getConfigs", mSettings.showtime, &S_timerResults);
|
2016-07-20 12:21:00 +02:00
|
|
|
configurations = preprocessor.getConfigs(tokens1);
|
|
|
|
} else {
|
2018-06-16 16:10:28 +02:00
|
|
|
configurations.insert(mSettings.userDefines);
|
2010-07-19 14:05:44 +02:00
|
|
|
}
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.checkConfiguration) {
|
2018-05-22 23:22:46 +02:00
|
|
|
for (const std::string &config : configurations)
|
|
|
|
(void)preprocessor.getcode(tokens1, config, files, true);
|
2016-07-21 12:47:00 +02:00
|
|
|
|
2013-08-31 18:38:52 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-12-11 10:22:06 +01:00
|
|
|
// Run define rules on raw code
|
2018-06-16 16:10:28 +02:00
|
|
|
for (const Settings::Rule &rule : mSettings.rules) {
|
2018-05-22 23:22:46 +02:00
|
|
|
if (rule.tokenlist != "define")
|
2016-07-20 12:21:00 +02:00
|
|
|
continue;
|
|
|
|
|
2016-07-28 15:35:41 +02:00
|
|
|
std::string code;
|
2016-07-28 13:40:52 +02:00
|
|
|
const std::list<Directive> &directives = preprocessor.getDirectives();
|
2018-05-22 23:22:46 +02:00
|
|
|
for (const Directive &dir : directives) {
|
|
|
|
if (dir.str.compare(0,8,"#define ") == 0)
|
|
|
|
code += "#line " + MathLib::toString(dir.linenr) + " \"" + dir.file + "\"\n" + dir.str + '\n';
|
2016-07-20 12:21:00 +02:00
|
|
|
}
|
2018-06-16 16:10:28 +02:00
|
|
|
Tokenizer tokenizer2(&mSettings, this);
|
2016-07-28 15:35:41 +02:00
|
|
|
std::istringstream istr2(code);
|
|
|
|
tokenizer2.list.createTokens(istr2);
|
|
|
|
executeRules("define", tokenizer2);
|
|
|
|
break;
|
2011-04-24 18:10:25 +02:00
|
|
|
}
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
if (!mSettings.force && configurations.size() > mSettings.maxConfigs) {
|
|
|
|
if (mSettings.isEnabled(Settings::INFORMATION)) {
|
2012-12-26 18:35:49 +01:00
|
|
|
tooManyConfigsError(Path::toNativeSeparators(filename),configurations.size());
|
|
|
|
} else {
|
2018-06-17 19:20:07 +02:00
|
|
|
mTooManyConfigs = true;
|
2012-12-26 18:35:49 +01:00
|
|
|
}
|
2012-05-09 18:54:43 +02:00
|
|
|
}
|
|
|
|
|
2014-09-02 18:05:02 +02:00
|
|
|
std::set<unsigned long long> checksums;
|
2012-05-11 19:38:19 +02:00
|
|
|
unsigned int checkCount = 0;
|
2018-05-06 22:02:23 +02:00
|
|
|
bool hasValidConfig = false;
|
2018-05-15 15:42:54 +02:00
|
|
|
std::list<std::string> configurationError;
|
2016-07-20 12:21:00 +02:00
|
|
|
for (std::set<std::string>::const_iterator it = configurations.begin(); it != configurations.end(); ++it) {
|
2015-12-11 10:22:06 +01:00
|
|
|
// bail out if terminated
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.terminated())
|
2015-12-11 10:22:06 +01:00
|
|
|
break;
|
|
|
|
|
2011-10-05 07:37:43 +02:00
|
|
|
// Check only a few configurations (default 12), after that bail out, unless --force
|
2011-04-24 18:10:25 +02:00
|
|
|
// was used.
|
2018-06-16 16:10:28 +02:00
|
|
|
if (!mSettings.force && ++checkCount > mSettings.maxConfigs)
|
2011-04-24 18:10:25 +02:00
|
|
|
break;
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2018-06-17 07:40:13 +02:00
|
|
|
mCurrentConfig = *it;
|
2010-08-07 13:08:36 +02:00
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
if (!mSettings.userDefines.empty()) {
|
2018-06-17 07:40:13 +02:00
|
|
|
if (!mCurrentConfig.empty())
|
|
|
|
mCurrentConfig = ";" + mCurrentConfig;
|
|
|
|
mCurrentConfig = mSettings.userDefines + mCurrentConfig;
|
2013-06-08 16:46:54 +02:00
|
|
|
}
|
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.preprocessOnly) {
|
|
|
|
Timer t("Preprocessor::getcode", mSettings.showtime, &S_timerResults);
|
2018-06-17 07:40:13 +02:00
|
|
|
std::string codeWithoutCfg = preprocessor.getcode(tokens1, mCurrentConfig, files, true);
|
2017-05-18 21:53:25 +02:00
|
|
|
t.Stop();
|
2010-04-15 22:45:38 +02:00
|
|
|
|
2016-01-02 11:48:36 +01:00
|
|
|
if (codeWithoutCfg.compare(0,5,"#file") == 0)
|
|
|
|
codeWithoutCfg.insert(0U, "//");
|
|
|
|
std::string::size_type pos = 0;
|
|
|
|
while ((pos = codeWithoutCfg.find("\n#file",pos)) != std::string::npos)
|
|
|
|
codeWithoutCfg.insert(pos+1U, "//");
|
|
|
|
pos = 0;
|
|
|
|
while ((pos = codeWithoutCfg.find("\n#endfile",pos)) != std::string::npos)
|
|
|
|
codeWithoutCfg.insert(pos+1U, "//");
|
|
|
|
pos = 0;
|
|
|
|
while ((pos = codeWithoutCfg.find(Preprocessor::macroChar,pos)) != std::string::npos)
|
|
|
|
codeWithoutCfg[pos] = ' ';
|
|
|
|
reportOut(codeWithoutCfg);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
Tokenizer mTokenizer(&mSettings, this);
|
|
|
|
if (mSettings.showtime != SHOWTIME_NONE)
|
|
|
|
mTokenizer.setTimerResults(&S_timerResults);
|
2015-12-11 10:22:06 +01:00
|
|
|
|
|
|
|
try {
|
2017-05-17 14:57:54 +02:00
|
|
|
bool result;
|
|
|
|
|
2015-12-11 10:22:06 +01:00
|
|
|
// Create tokens, skip rest of iteration if failed
|
2018-06-16 16:10:28 +02:00
|
|
|
Timer timer("Tokenizer::createTokens", mSettings.showtime, &S_timerResults);
|
2018-06-17 07:40:13 +02:00
|
|
|
const simplecpp::TokenList &tokensP = preprocessor.preprocess(tokens1, mCurrentConfig, files, true);
|
2018-06-16 16:10:28 +02:00
|
|
|
mTokenizer.createTokens(&tokensP);
|
2015-12-11 10:22:06 +01:00
|
|
|
timer.Stop();
|
2018-05-15 15:42:54 +02:00
|
|
|
hasValidConfig = true;
|
2018-05-17 10:27:05 +02:00
|
|
|
|
|
|
|
// If only errors are printed, print filename after the check
|
2018-06-17 07:40:13 +02:00
|
|
|
if (!mSettings.quiet && (!mCurrentConfig.empty() || it != configurations.begin())) {
|
2018-05-17 10:27:05 +02:00
|
|
|
std::string fixedpath = Path::simplifyPath(filename);
|
|
|
|
fixedpath = Path::toNativeSeparators(fixedpath);
|
2018-06-17 07:40:13 +02:00
|
|
|
mErrorLogger.reportOut("Checking " + fixedpath + ": " + mCurrentConfig + "...");
|
2018-05-17 10:27:05 +02:00
|
|
|
}
|
|
|
|
|
2017-05-18 21:53:25 +02:00
|
|
|
if (tokensP.empty())
|
2017-05-17 22:30:20 +02:00
|
|
|
continue;
|
2015-12-11 10:22:06 +01:00
|
|
|
|
|
|
|
// skip rest of iteration if just checking configuration
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.checkConfiguration)
|
2015-12-11 10:22:06 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// Check raw tokens
|
2018-06-16 16:10:28 +02:00
|
|
|
checkRawTokens(mTokenizer);
|
2015-12-11 10:22:06 +01:00
|
|
|
|
|
|
|
// Simplify tokens into normal form, skip rest of iteration if failed
|
2018-06-16 16:10:28 +02:00
|
|
|
Timer timer2("Tokenizer::simplifyTokens1", mSettings.showtime, &S_timerResults);
|
2018-06-17 07:40:13 +02:00
|
|
|
result = mTokenizer.simplifyTokens1(mCurrentConfig);
|
2015-12-11 10:22:06 +01:00
|
|
|
timer2.Stop();
|
|
|
|
if (!result)
|
|
|
|
continue;
|
|
|
|
|
2015-12-14 09:37:26 +01:00
|
|
|
// dump xml if --dump
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.dump && fdump.is_open()) {
|
2018-06-17 07:40:13 +02:00
|
|
|
fdump << "<dump cfg=\"" << ErrorLogger::toxml(mCurrentConfig) << "\">" << std::endl;
|
2015-12-07 19:54:41 +01:00
|
|
|
preprocessor.dump(fdump);
|
2018-06-16 16:10:28 +02:00
|
|
|
mTokenizer.dump(fdump);
|
2015-12-14 20:05:17 +01:00
|
|
|
fdump << "</dump>" << std::endl;
|
2015-12-11 10:22:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Skip if we already met the same simplified token list
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.force || mSettings.maxConfigs > 1) {
|
|
|
|
const unsigned long long checksum = mTokenizer.list.calculateChecksum();
|
2016-08-21 12:31:26 +02:00
|
|
|
if (checksums.find(checksum) != checksums.end()) {
|
2018-08-05 11:19:20 +02:00
|
|
|
if (mSettings.debugwarnings)
|
2018-06-17 07:40:13 +02:00
|
|
|
purgedConfigurationMessage(filename, mCurrentConfig);
|
2015-12-11 10:22:06 +01:00
|
|
|
continue;
|
2016-08-21 12:31:26 +02:00
|
|
|
}
|
2015-12-11 10:22:06 +01:00
|
|
|
checksums.insert(checksum);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check normal tokens
|
2018-06-16 16:10:28 +02:00
|
|
|
checkNormalTokens(mTokenizer);
|
2015-12-11 10:22:06 +01:00
|
|
|
|
2016-11-07 21:49:58 +01:00
|
|
|
// Analyze info..
|
2018-06-16 16:10:28 +02:00
|
|
|
if (!mSettings.buildDir.empty())
|
|
|
|
checkUnusedFunctions.parseTokens(mTokenizer, filename.c_str(), &mSettings);
|
2016-11-07 21:49:58 +01:00
|
|
|
|
2015-12-11 10:22:06 +01:00
|
|
|
// simplify more if required, skip rest of iteration if failed
|
2018-06-17 07:37:10 +02:00
|
|
|
if (mSimplify) {
|
2015-12-11 10:22:06 +01:00
|
|
|
// if further simplification fails then skip rest of iteration
|
2018-06-16 16:10:28 +02:00
|
|
|
Timer timer3("Tokenizer::simplifyTokenList2", mSettings.showtime, &S_timerResults);
|
|
|
|
result = mTokenizer.simplifyTokenList2();
|
2015-12-11 10:22:06 +01:00
|
|
|
timer3.Stop();
|
|
|
|
if (!result)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Check simplified tokens
|
2018-06-16 16:10:28 +02:00
|
|
|
checkSimplifiedTokens(mTokenizer);
|
2015-12-11 10:22:06 +01:00
|
|
|
}
|
|
|
|
|
2018-05-15 15:42:54 +02:00
|
|
|
} catch (const simplecpp::Output &o) {
|
|
|
|
// #error etc during preprocessing
|
2018-06-17 07:40:13 +02:00
|
|
|
configurationError.push_back((mCurrentConfig.empty() ? "\'\'" : mCurrentConfig) + " : [" + o.location.file() + ':' + MathLib::toString(o.location.line) + "] " + o.msg);
|
2018-05-15 15:42:54 +02:00
|
|
|
--checkCount; // don't count invalid configurations
|
|
|
|
continue;
|
|
|
|
|
2015-12-11 10:22:06 +01:00
|
|
|
} catch (const InternalError &e) {
|
|
|
|
internalErrorFound=true;
|
|
|
|
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
|
|
|
ErrorLogger::ErrorMessage::FileLocation loc;
|
|
|
|
if (e.token) {
|
|
|
|
loc.line = e.token->linenr();
|
2018-06-16 16:10:28 +02:00
|
|
|
const std::string fixedpath = Path::toNativeSeparators(mTokenizer.list.file(e.token));
|
2015-12-11 10:22:06 +01:00
|
|
|
loc.setfile(fixedpath);
|
|
|
|
} else {
|
|
|
|
ErrorLogger::ErrorMessage::FileLocation loc2;
|
2016-07-26 16:27:55 +02:00
|
|
|
loc2.setfile(Path::toNativeSeparators(filename));
|
2015-12-11 10:22:06 +01:00
|
|
|
locationList.push_back(loc2);
|
2018-06-16 16:10:28 +02:00
|
|
|
loc.setfile(mTokenizer.list.getSourceFilePath());
|
2015-12-11 10:22:06 +01:00
|
|
|
}
|
|
|
|
locationList.push_back(loc);
|
2016-07-26 16:27:55 +02:00
|
|
|
ErrorLogger::ErrorMessage errmsg(locationList,
|
2018-06-16 16:10:28 +02:00
|
|
|
mTokenizer.list.getSourceFilePath(),
|
2016-07-26 16:27:55 +02:00
|
|
|
Severity::error,
|
|
|
|
e.errorMessage,
|
|
|
|
e.id,
|
|
|
|
false);
|
2015-12-11 10:22:06 +01:00
|
|
|
|
|
|
|
reportErr(errmsg);
|
2011-08-16 21:58:27 +02:00
|
|
|
}
|
2010-04-13 19:25:08 +02:00
|
|
|
}
|
2015-12-11 10:22:06 +01:00
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
if (!hasValidConfig && configurations.size() > 1 && mSettings.isEnabled(Settings::INFORMATION)) {
|
2018-05-15 15:42:54 +02:00
|
|
|
std::string msg;
|
2018-05-17 10:27:05 +02:00
|
|
|
msg = "This file is not analyzed. Cppcheck failed to extract a valid configuration. Use -v for more details.";
|
|
|
|
msg += "\nThis file is not analyzed. Cppcheck failed to extract a valid configuration. The tested configurations have these preprocessor errors:";
|
2018-05-15 15:42:54 +02:00
|
|
|
for (const std::string &s : configurationError)
|
2018-05-17 10:27:05 +02:00
|
|
|
msg += '\n' + s;
|
2018-05-15 15:42:54 +02:00
|
|
|
|
2018-05-06 22:02:23 +02:00
|
|
|
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
|
|
|
ErrorLogger::ErrorMessage::FileLocation loc;
|
|
|
|
loc.setfile(Path::toNativeSeparators(filename));
|
|
|
|
locationList.push_back(loc);
|
|
|
|
ErrorLogger::ErrorMessage errmsg(locationList,
|
|
|
|
loc.getfile(),
|
|
|
|
Severity::information,
|
2018-05-15 15:42:54 +02:00
|
|
|
msg,
|
2018-05-06 22:02:23 +02:00
|
|
|
"noValidConfiguration",
|
|
|
|
false);
|
|
|
|
reportErr(errmsg);
|
|
|
|
}
|
|
|
|
|
2015-12-14 09:37:26 +01:00
|
|
|
// dumped all configs, close root </dumps> element now
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.dump && fdump.is_open())
|
2015-12-14 09:37:26 +01:00
|
|
|
fdump << "</dumps>" << std::endl;
|
|
|
|
|
2012-04-16 16:25:04 +02:00
|
|
|
} catch (const std::runtime_error &e) {
|
2013-05-09 18:50:24 +02:00
|
|
|
internalError(filename, e.what());
|
2016-05-28 13:24:19 +02:00
|
|
|
} catch (const std::bad_alloc &e) {
|
2016-05-30 09:17:40 +02:00
|
|
|
internalError(filename, e.what());
|
2013-05-09 18:50:24 +02:00
|
|
|
} catch (const InternalError &e) {
|
|
|
|
internalError(filename, e.errorMessage);
|
2018-06-17 07:43:25 +02:00
|
|
|
mExitCode=1; // e.g. reflect a syntax error
|
2011-04-24 18:10:25 +02:00
|
|
|
}
|
|
|
|
|
2018-06-17 07:31:34 +02:00
|
|
|
mAnalyzerInformation.setFileInfo("CheckUnusedFunctions", checkUnusedFunctions.analyzerInfo());
|
|
|
|
mAnalyzerInformation.close();
|
2016-10-29 12:18:11 +02:00
|
|
|
|
2015-01-07 19:26:16 +01:00
|
|
|
// In jointSuppressionReport mode, unmatched suppressions are
|
|
|
|
// collected after all files are processed
|
2018-06-16 16:10:28 +02:00
|
|
|
if (!mSettings.jointSuppressionReport && (mSettings.isEnabled(Settings::INFORMATION) || mSettings.checkConfiguration)) {
|
|
|
|
reportUnmatchedSuppressions(mSettings.nomsg.getUnmatchedLocalSuppressions(filename, isUnusedFunctionCheckEnabled()));
|
2015-01-07 19:26:16 +01:00
|
|
|
}
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2018-06-16 23:31:16 +02:00
|
|
|
mErrorList.clear();
|
2018-06-17 07:43:25 +02:00
|
|
|
if (internalErrorFound && (mExitCode==0)) {
|
|
|
|
mExitCode = 1;
|
2015-05-25 21:15:55 +02:00
|
|
|
}
|
2018-06-17 07:43:25 +02:00
|
|
|
return mExitCode;
|
2011-07-25 13:25:09 +02:00
|
|
|
}
|
|
|
|
|
2013-05-09 18:50:24 +02:00
|
|
|
void CppCheck::internalError(const std::string &filename, const std::string &msg)
|
|
|
|
{
|
|
|
|
const std::string fixedpath = Path::toNativeSeparators(filename);
|
2015-01-12 23:09:17 +01:00
|
|
|
const std::string fullmsg("Bailing out from checking " + fixedpath + " since there was an internal error: " + msg);
|
2013-05-09 18:50:24 +02:00
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.isEnabled(Settings::INFORMATION)) {
|
2013-05-09 18:50:24 +02:00
|
|
|
const ErrorLogger::ErrorMessage::FileLocation loc1(filename, 0);
|
2018-04-09 09:54:39 +02:00
|
|
|
std::list<ErrorLogger::ErrorMessage::FileLocation> callstack(1, loc1);
|
2013-05-09 18:50:24 +02:00
|
|
|
|
|
|
|
ErrorLogger::ErrorMessage errmsg(callstack,
|
2016-07-26 16:27:55 +02:00
|
|
|
emptyString,
|
2013-05-09 18:50:24 +02:00
|
|
|
Severity::information,
|
|
|
|
fullmsg,
|
|
|
|
"internalError",
|
|
|
|
false);
|
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
mErrorLogger.reportErr(errmsg);
|
2013-05-09 18:50:24 +02:00
|
|
|
} else {
|
|
|
|
// Report on stdout
|
2018-06-16 16:10:28 +02:00
|
|
|
mErrorLogger.reportOut(fullmsg);
|
2013-05-09 18:50:24 +02:00
|
|
|
}
|
|
|
|
}
|
2011-08-16 21:58:27 +02:00
|
|
|
|
2010-04-13 19:25:08 +02:00
|
|
|
//---------------------------------------------------------------------------
|
2015-12-11 10:22:06 +01:00
|
|
|
// CppCheck - A function that checks a raw token list
|
2010-04-13 19:25:08 +02:00
|
|
|
//---------------------------------------------------------------------------
|
2015-12-11 10:22:06 +01:00
|
|
|
void CppCheck::checkRawTokens(const Tokenizer &tokenizer)
|
2010-04-13 19:25:08 +02:00
|
|
|
{
|
2015-12-11 10:22:06 +01:00
|
|
|
// Execute rules for "raw" code
|
|
|
|
executeRules("raw", tokenizer);
|
|
|
|
}
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2015-12-11 10:22:06 +01:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// CppCheck - A function that checks a normal token list
|
|
|
|
//---------------------------------------------------------------------------
|
2014-11-24 06:37:08 +01:00
|
|
|
|
2015-12-11 10:22:06 +01:00
|
|
|
void CppCheck::checkNormalTokens(const Tokenizer &tokenizer)
|
|
|
|
{
|
|
|
|
// call all "runChecks" in all registered Check classes
|
|
|
|
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) {
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.terminated())
|
2015-12-11 10:22:06 +01:00
|
|
|
return;
|
2013-06-09 14:58:56 +02:00
|
|
|
|
2016-02-11 16:10:52 +01:00
|
|
|
if (tokenizer.isMaxTime())
|
|
|
|
return;
|
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
Timer timerRunChecks((*it)->name() + "::runChecks", mSettings.showtime, &S_timerResults);
|
|
|
|
(*it)->runChecks(&tokenizer, &mSettings, this);
|
2015-12-11 10:22:06 +01:00
|
|
|
}
|
2013-05-11 11:35:04 +02:00
|
|
|
|
2015-12-11 10:22:06 +01:00
|
|
|
// Analyse the tokens..
|
|
|
|
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) {
|
2018-06-16 16:10:28 +02:00
|
|
|
Check::FileInfo *fi = (*it)->getFileInfo(&tokenizer, &mSettings);
|
2016-10-29 12:18:11 +02:00
|
|
|
if (fi != nullptr) {
|
2018-06-17 07:36:05 +02:00
|
|
|
mFileInfo.push_back(fi);
|
2018-06-17 07:31:34 +02:00
|
|
|
mAnalyzerInformation.setFileInfo((*it)->name(), fi->toString());
|
2016-10-29 12:18:11 +02:00
|
|
|
}
|
2015-12-11 10:22:06 +01:00
|
|
|
}
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2015-12-11 10:22:06 +01:00
|
|
|
executeRules("normal", tokenizer);
|
|
|
|
}
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2015-12-11 10:22:06 +01:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// CppCheck - A function that checks a simplified token list
|
|
|
|
//---------------------------------------------------------------------------
|
2010-12-12 11:56:22 +01:00
|
|
|
|
2015-12-11 10:22:06 +01:00
|
|
|
void CppCheck::checkSimplifiedTokens(const Tokenizer &tokenizer)
|
|
|
|
{
|
|
|
|
// call all "runSimplifiedChecks" in all registered Check classes
|
|
|
|
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) {
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.terminated())
|
2015-12-11 10:22:06 +01:00
|
|
|
return;
|
2013-07-24 13:06:59 +02:00
|
|
|
|
2016-02-11 16:10:52 +01:00
|
|
|
if (tokenizer.isMaxTime())
|
|
|
|
return;
|
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
Timer timerSimpleChecks((*it)->name() + "::runSimplifiedChecks", mSettings.showtime, &S_timerResults);
|
|
|
|
(*it)->runSimplifiedChecks(&tokenizer, &mSettings, this);
|
2015-12-11 10:22:06 +01:00
|
|
|
timerSimpleChecks.Stop();
|
2011-11-20 23:41:26 +01:00
|
|
|
}
|
2015-12-11 10:22:06 +01:00
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
if (!mSettings.terminated())
|
2015-12-11 10:22:06 +01:00
|
|
|
executeRules("simple", tokenizer);
|
2010-04-13 19:25:08 +02:00
|
|
|
}
|
|
|
|
|
2013-06-09 14:58:56 +02:00
|
|
|
void CppCheck::executeRules(const std::string &tokenlist, const Tokenizer &tokenizer)
|
|
|
|
{
|
2013-06-12 06:43:52 +02:00
|
|
|
(void)tokenlist;
|
|
|
|
(void)tokenizer;
|
2013-06-09 20:17:26 +02:00
|
|
|
|
|
|
|
#ifdef HAVE_RULES
|
2013-06-09 14:58:56 +02:00
|
|
|
// Are there rules to execute?
|
|
|
|
bool isrule = false;
|
2018-06-16 16:10:28 +02:00
|
|
|
for (std::list<Settings::Rule>::const_iterator it = mSettings.rules.begin(); it != mSettings.rules.end(); ++it) {
|
2015-10-09 21:56:19 +02:00
|
|
|
if (it->tokenlist == tokenlist)
|
2013-06-09 14:58:56 +02:00
|
|
|
isrule = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// There is no rule to execute
|
|
|
|
if (isrule == false)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Write all tokens in a string that can be parsed by pcre
|
|
|
|
std::ostringstream ostr;
|
|
|
|
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next())
|
|
|
|
ostr << " " << tok->str();
|
|
|
|
const std::string str(ostr.str());
|
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
for (std::list<Settings::Rule>::const_iterator it = mSettings.rules.begin(); it != mSettings.rules.end(); ++it) {
|
2015-10-09 21:56:19 +02:00
|
|
|
const Settings::Rule &rule = *it;
|
2015-11-28 12:30:03 +01:00
|
|
|
if (rule.pattern.empty() || rule.id.empty() || rule.severity == Severity::none || rule.tokenlist != tokenlist)
|
2013-06-09 14:58:56 +02:00
|
|
|
continue;
|
|
|
|
|
2014-02-16 11:47:52 +01:00
|
|
|
const char *error = nullptr;
|
2013-06-09 14:58:56 +02:00
|
|
|
int erroffset = 0;
|
2014-02-15 08:46:28 +01:00
|
|
|
pcre *re = pcre_compile(rule.pattern.c_str(),0,&error,&erroffset,nullptr);
|
2013-06-09 14:58:56 +02:00
|
|
|
if (!re) {
|
|
|
|
if (error) {
|
|
|
|
ErrorLogger::ErrorMessage errmsg(std::list<ErrorLogger::ErrorMessage::FileLocation>(),
|
2016-07-26 17:10:05 +02:00
|
|
|
emptyString,
|
2013-06-09 14:58:56 +02:00
|
|
|
Severity::error,
|
|
|
|
error,
|
|
|
|
"pcre_compile",
|
|
|
|
false);
|
|
|
|
|
|
|
|
reportErr(errmsg);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
int pos = 0;
|
2015-05-25 21:15:55 +02:00
|
|
|
int ovector[30]= {0};
|
2014-02-15 08:46:28 +01:00
|
|
|
while (pos < (int)str.size() && 0 <= pcre_exec(re, nullptr, str.c_str(), (int)str.size(), pos, 0, ovector, 30)) {
|
2015-05-25 21:15:55 +02:00
|
|
|
const unsigned int pos1 = (unsigned int)ovector[0];
|
|
|
|
const unsigned int pos2 = (unsigned int)ovector[1];
|
2013-06-09 14:58:56 +02:00
|
|
|
|
|
|
|
// jump to the end of the match for the next pcre_exec
|
|
|
|
pos = (int)pos2;
|
|
|
|
|
|
|
|
// determine location..
|
|
|
|
ErrorLogger::ErrorMessage::FileLocation loc;
|
2014-06-04 19:18:27 +02:00
|
|
|
loc.setfile(tokenizer.list.getSourceFilePath());
|
2013-06-09 14:58:56 +02:00
|
|
|
loc.line = 0;
|
|
|
|
|
|
|
|
std::size_t len = 0;
|
|
|
|
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {
|
|
|
|
len = len + 1U + tok->str().size();
|
|
|
|
if (len > pos1) {
|
|
|
|
loc.setfile(tokenizer.list.getFiles().at(tok->fileIndex()));
|
|
|
|
loc.line = tok->linenr();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::list<ErrorLogger::ErrorMessage::FileLocation> callStack(1, loc);
|
|
|
|
|
|
|
|
// Create error message
|
|
|
|
std::string summary;
|
|
|
|
if (rule.summary.empty())
|
|
|
|
summary = "found '" + str.substr(pos1, pos2 - pos1) + "'";
|
|
|
|
else
|
|
|
|
summary = rule.summary;
|
2016-07-26 17:10:05 +02:00
|
|
|
const ErrorLogger::ErrorMessage errmsg(callStack, tokenizer.list.getSourceFilePath(), rule.severity, summary, rule.id, false);
|
2013-06-09 14:58:56 +02:00
|
|
|
|
|
|
|
// Report error
|
|
|
|
reportErr(errmsg);
|
|
|
|
}
|
|
|
|
|
|
|
|
pcre_free(re);
|
|
|
|
}
|
2013-06-09 20:17:26 +02:00
|
|
|
#endif
|
2013-06-09 14:58:56 +02:00
|
|
|
}
|
|
|
|
|
2011-02-16 02:12:15 +01:00
|
|
|
Settings &CppCheck::settings()
|
2010-04-13 19:25:08 +02:00
|
|
|
{
|
2018-06-16 16:10:28 +02:00
|
|
|
return mSettings;
|
2010-04-13 19:25:08 +02:00
|
|
|
}
|
|
|
|
|
2012-12-26 18:35:49 +01:00
|
|
|
void CppCheck::tooManyConfigsError(const std::string &file, const std::size_t numberOfConfigurations)
|
|
|
|
{
|
2018-06-17 19:20:07 +02:00
|
|
|
if (!mSettings.isEnabled(Settings::INFORMATION) && !mTooManyConfigs)
|
2012-12-26 18:35:49 +01:00
|
|
|
return;
|
|
|
|
|
2018-06-17 19:20:07 +02:00
|
|
|
mTooManyConfigs = false;
|
2012-12-26 18:35:49 +01:00
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.isEnabled(Settings::INFORMATION) && file.empty())
|
2012-12-26 18:35:49 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
std::list<ErrorLogger::ErrorMessage::FileLocation> loclist;
|
|
|
|
if (!file.empty()) {
|
|
|
|
ErrorLogger::ErrorMessage::FileLocation location;
|
|
|
|
location.setfile(file);
|
|
|
|
loclist.push_back(location);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ostringstream msg;
|
2018-06-16 16:10:28 +02:00
|
|
|
msg << "Too many #ifdef configurations - cppcheck only checks " << mSettings.maxConfigs;
|
|
|
|
if (numberOfConfigurations > mSettings.maxConfigs)
|
2012-12-26 18:35:49 +01:00
|
|
|
msg << " of " << numberOfConfigurations << " configurations. Use --force to check all configurations.\n";
|
|
|
|
if (file.empty())
|
|
|
|
msg << " configurations. Use --force to check all configurations. For more details, use --enable=information.\n";
|
|
|
|
msg << "The checking of the file will be interrupted because there are too many "
|
|
|
|
"#ifdef configurations. Checking of all #ifdef configurations can be forced "
|
|
|
|
"by --force command line option or from GUI preferences. However that may "
|
|
|
|
"increase the checking time.";
|
|
|
|
if (file.empty())
|
|
|
|
msg << " For more details, use --enable=information.";
|
|
|
|
|
|
|
|
|
|
|
|
ErrorLogger::ErrorMessage errmsg(loclist,
|
2016-07-26 16:27:55 +02:00
|
|
|
emptyString,
|
2012-12-26 18:35:49 +01:00
|
|
|
Severity::information,
|
|
|
|
msg.str(),
|
Mapped toomanyconfigs ,AssignmentAddressToInteger
,AssignmentIntegerToAddress ,CastIntegerToAddressAtReturn
,CastAddressToIntegerAtReturn ,assertWithSideEffect ,assignmentInAssert
,uselessAssignmentArg ,uselessAssignmentPtrArg
,comparisonOfFuncReturningBoolError
,comparisonOfTwoFuncsReturningBoolError ,comparisonOfBoolWithBoolError
,incrementboolean ,comparisonOfBoolWithInt ,compareBoolExpressionWithInt
,negativeIndex ,pointerOutOfBounds ,arrayIndexThenCheck
,possibleBufferAccessOutOfBounds ,argumentSize
,arrayIndexOutOfBoundsCond ,noConstructor ,copyCtorPointerCopying
,noCopyConstructor ,uninitMemberVar ,operatorEqVarError
,unusedPrivateFunction ,memsetClassFloat ,mallocOnClassWarning
,operatorEq ,thisSubtraction ,operatorEqRetRefThis ,operatorEqToSelf
,useInitializationList ,duplInheritedMember ,assignIfError
,comparisonError ,multiCondition ,mismatchingBitAnd
,oppositeInnerCondition ,incorrectLogicOperator ,redundantCondition
,moduloAlwaysTrueFalse to their CWEs ids.
2016-02-20 23:56:36 +01:00
|
|
|
"toomanyconfigs", CWE398,
|
2012-12-26 18:35:49 +01:00
|
|
|
false);
|
|
|
|
|
|
|
|
reportErr(errmsg);
|
|
|
|
}
|
|
|
|
|
2014-09-02 18:05:02 +02:00
|
|
|
void CppCheck::purgedConfigurationMessage(const std::string &file, const std::string& configuration)
|
|
|
|
{
|
2018-06-17 19:20:07 +02:00
|
|
|
mTooManyConfigs = false;
|
2014-09-02 18:05:02 +02:00
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.isEnabled(Settings::INFORMATION) && file.empty())
|
2014-09-02 18:05:02 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
std::list<ErrorLogger::ErrorMessage::FileLocation> loclist;
|
|
|
|
if (!file.empty()) {
|
|
|
|
ErrorLogger::ErrorMessage::FileLocation location;
|
|
|
|
location.setfile(file);
|
|
|
|
loclist.push_back(location);
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorLogger::ErrorMessage errmsg(loclist,
|
2016-07-26 16:27:55 +02:00
|
|
|
emptyString,
|
2014-09-02 18:05:02 +02:00
|
|
|
Severity::information,
|
|
|
|
"The configuration '" + configuration + "' was not checked because its code equals another one.",
|
2014-09-10 20:19:04 +02:00
|
|
|
"purgedConfiguration",
|
2014-09-02 18:05:02 +02:00
|
|
|
false);
|
|
|
|
|
|
|
|
reportErr(errmsg);
|
|
|
|
}
|
|
|
|
|
2010-04-13 19:25:08 +02:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void CppCheck::reportErr(const ErrorLogger::ErrorMessage &msg)
|
|
|
|
{
|
2018-06-16 16:10:28 +02:00
|
|
|
if (!mSettings.library.reportErrors(msg.file0))
|
2013-10-20 14:09:10 +02:00
|
|
|
return;
|
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
const std::string errmsg = msg.toString(mSettings.verbose);
|
2011-04-10 21:51:27 +02:00
|
|
|
if (errmsg.empty())
|
|
|
|
return;
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2012-04-06 18:16:59 +02:00
|
|
|
// Alert only about unique errors
|
2018-06-16 23:31:16 +02:00
|
|
|
if (std::find(mErrorList.begin(), mErrorList.end(), errmsg) != mErrorList.end())
|
2012-04-06 18:16:59 +02:00
|
|
|
return;
|
|
|
|
|
2018-04-09 06:43:48 +02:00
|
|
|
const Suppressions::ErrorMessage errorMessage = msg.toSuppressionsErrorMessage();
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2018-06-17 07:29:07 +02:00
|
|
|
if (mUseGlobalSuppressions) {
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.nomsg.isSuppressed(errorMessage))
|
2018-05-11 09:01:08 +02:00
|
|
|
return;
|
|
|
|
} else {
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.nomsg.isSuppressedLocal(errorMessage))
|
2018-05-11 09:01:08 +02:00
|
|
|
return;
|
|
|
|
}
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2018-06-17 07:29:07 +02:00
|
|
|
if (!mSettings.nofail.isSuppressed(errorMessage) && (mUseGlobalSuppressions || !mSettings.nomsg.isSuppressed(errorMessage)))
|
2018-06-17 07:43:25 +02:00
|
|
|
mExitCode = 1;
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2018-06-16 23:31:16 +02:00
|
|
|
mErrorList.push_back(errmsg);
|
2012-04-06 18:16:59 +02:00
|
|
|
|
2018-06-16 16:10:28 +02:00
|
|
|
mErrorLogger.reportErr(msg);
|
2018-06-17 07:31:34 +02:00
|
|
|
mAnalyzerInformation.reportErr(msg, mSettings.verbose);
|
2018-06-16 16:10:28 +02:00
|
|
|
if (!mSettings.plistOutput.empty() && plistFile.is_open()) {
|
2017-05-16 14:07:23 +02:00
|
|
|
plistFile << ErrorLogger::plistData(msg);
|
|
|
|
}
|
2010-04-13 19:25:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CppCheck::reportOut(const std::string &outmsg)
|
|
|
|
{
|
2018-06-16 16:10:28 +02:00
|
|
|
mErrorLogger.reportOut(outmsg);
|
2010-04-13 19:25:08 +02:00
|
|
|
}
|
|
|
|
|
2012-07-08 23:39:46 +02:00
|
|
|
void CppCheck::reportProgress(const std::string &filename, const char stage[], const std::size_t value)
|
2010-04-13 19:25:08 +02:00
|
|
|
{
|
2018-06-16 16:10:28 +02:00
|
|
|
mErrorLogger.reportProgress(filename, stage, value);
|
2010-04-13 19:25:08 +02:00
|
|
|
}
|
|
|
|
|
2012-06-18 23:15:48 +02:00
|
|
|
void CppCheck::reportInfo(const ErrorLogger::ErrorMessage &msg)
|
|
|
|
{
|
2018-04-09 06:43:48 +02:00
|
|
|
const Suppressions::ErrorMessage &errorMessage = msg.toSuppressionsErrorMessage();
|
2018-06-16 16:10:28 +02:00
|
|
|
if (!mSettings.nomsg.isSuppressed(errorMessage))
|
|
|
|
mErrorLogger.reportInfo(msg);
|
2012-06-18 23:15:48 +02:00
|
|
|
}
|
|
|
|
|
2012-07-08 23:39:46 +02:00
|
|
|
void CppCheck::reportStatus(unsigned int /*fileindex*/, unsigned int /*filecount*/, std::size_t /*sizedone*/, std::size_t /*sizetotal*/)
|
2010-08-03 16:36:21 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-04-13 19:25:08 +02:00
|
|
|
void CppCheck::getErrorMessages()
|
|
|
|
{
|
2018-06-16 16:10:28 +02:00
|
|
|
Settings s(mSettings);
|
2015-01-06 15:08:25 +01:00
|
|
|
s.addEnabled("warning");
|
|
|
|
s.addEnabled("style");
|
|
|
|
s.addEnabled("portability");
|
|
|
|
s.addEnabled("performance");
|
|
|
|
s.addEnabled("information");
|
|
|
|
|
2018-02-10 22:30:49 +01:00
|
|
|
purgedConfigurationMessage("","");
|
|
|
|
|
2018-06-17 19:20:07 +02:00
|
|
|
mTooManyConfigs = true;
|
2012-12-26 18:35:49 +01:00
|
|
|
tooManyConfigsError("",0U);
|
|
|
|
|
2010-04-13 19:25:08 +02:00
|
|
|
// call all "getErrorMessages" in all registered Check classes
|
2014-04-13 11:51:29 +02:00
|
|
|
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it)
|
2015-01-06 15:08:25 +01:00
|
|
|
(*it)->getErrorMessages(this, &s);
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2015-01-06 15:08:25 +01:00
|
|
|
Preprocessor::getErrorMessages(this, &s);
|
2010-04-13 19:25:08 +02:00
|
|
|
}
|
2014-11-15 10:43:49 +01:00
|
|
|
|
2018-01-12 08:24:01 +01:00
|
|
|
bool CppCheck::analyseWholeProgram()
|
2014-11-15 10:43:49 +01:00
|
|
|
{
|
2018-01-12 08:24:01 +01:00
|
|
|
bool errors = false;
|
2015-01-07 19:26:16 +01:00
|
|
|
// Analyse the tokens
|
2014-11-15 10:43:49 +01:00
|
|
|
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it)
|
2018-06-17 07:36:05 +02:00
|
|
|
errors |= (*it)->analyseWholeProgram(mFileInfo, mSettings, *this);
|
2018-06-17 07:43:25 +02:00
|
|
|
return errors && (mExitCode > 0);
|
2014-11-15 10:43:49 +01:00
|
|
|
}
|
|
|
|
|
2016-11-05 21:26:56 +01:00
|
|
|
void CppCheck::analyseWholeProgram(const std::string &buildDir, const std::map<std::string, std::size_t> &files)
|
|
|
|
{
|
2016-12-08 22:46:44 +01:00
|
|
|
(void)files;
|
2016-11-05 21:26:56 +01:00
|
|
|
if (buildDir.empty())
|
|
|
|
return;
|
2018-06-16 16:10:28 +02:00
|
|
|
if (mSettings.isEnabled(Settings::UNUSED_FUNCTION))
|
2016-12-08 22:46:44 +01:00
|
|
|
CheckUnusedFunctions::analyseWholeProgram(this, buildDir);
|
2017-03-30 10:14:17 +02:00
|
|
|
std::list<Check::FileInfo*> fileInfoList;
|
|
|
|
|
|
|
|
// Load all analyzer info data..
|
|
|
|
const std::string filesTxt(buildDir + "/files.txt");
|
2018-04-11 09:50:42 +02:00
|
|
|
std::ifstream fin(filesTxt);
|
2017-03-30 10:14:17 +02:00
|
|
|
std::string filesTxtLine;
|
|
|
|
while (std::getline(fin, filesTxtLine)) {
|
|
|
|
const std::string::size_type firstColon = filesTxtLine.find(':');
|
|
|
|
if (firstColon == std::string::npos)
|
|
|
|
continue;
|
|
|
|
const std::string::size_type lastColon = filesTxtLine.rfind(':');
|
|
|
|
if (firstColon == lastColon)
|
|
|
|
continue;
|
|
|
|
const std::string xmlfile = buildDir + '/' + filesTxtLine.substr(0,firstColon);
|
2017-03-30 11:20:04 +02:00
|
|
|
//const std::string sourcefile = filesTxtLine.substr(lastColon+1);
|
2017-03-30 10:14:17 +02:00
|
|
|
|
|
|
|
tinyxml2::XMLDocument doc;
|
2018-05-29 13:24:48 +02:00
|
|
|
const tinyxml2::XMLError error = doc.LoadFile(xmlfile.c_str());
|
2017-03-30 10:14:17 +02:00
|
|
|
if (error != tinyxml2::XML_SUCCESS)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const tinyxml2::XMLElement * const rootNode = doc.FirstChildElement();
|
|
|
|
if (rootNode == nullptr)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (const tinyxml2::XMLElement *e = rootNode->FirstChildElement(); e; e = e->NextSiblingElement()) {
|
|
|
|
if (std::strcmp(e->Name(), "FileInfo") != 0)
|
|
|
|
continue;
|
|
|
|
const char *checkClassAttr = e->Attribute("check");
|
|
|
|
if (!checkClassAttr)
|
|
|
|
continue;
|
|
|
|
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it) {
|
|
|
|
if (checkClassAttr == (*it)->name())
|
|
|
|
fileInfoList.push_back((*it)->loadFileInfoFromXml(e));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Analyse the tokens
|
|
|
|
for (std::list<Check *>::const_iterator it = Check::instances().begin(); it != Check::instances().end(); ++it)
|
2018-06-16 16:10:28 +02:00
|
|
|
(*it)->analyseWholeProgram(fileInfoList, mSettings, *this);
|
2017-03-30 10:14:17 +02:00
|
|
|
|
|
|
|
for (std::list<Check::FileInfo*>::iterator fi = fileInfoList.begin(); fi != fileInfoList.end(); ++fi)
|
2018-01-08 20:20:33 +01:00
|
|
|
delete (*fi);
|
2016-11-05 21:26:56 +01:00
|
|
|
}
|
|
|
|
|
2016-10-28 12:10:19 +02:00
|
|
|
bool CppCheck::isUnusedFunctionCheckEnabled() const
|
2015-01-07 19:26:16 +01:00
|
|
|
{
|
2018-06-16 16:10:28 +02:00
|
|
|
return (mSettings.jobs == 1 && mSettings.isEnabled(Settings::UNUSED_FUNCTION));
|
2015-01-07 19:26:16 +01:00
|
|
|
}
|