2010-04-13 19:25:08 +02:00
|
|
|
/*
|
|
|
|
* Cppcheck - A tool for static C/C++ code analysis
|
2016-01-01 14:34:45 +01:00
|
|
|
* Copyright (C) 2007-2016 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"
|
|
|
|
|
2011-12-08 17:42:26 +01:00
|
|
|
#include "preprocessor.h" // Preprocessor
|
|
|
|
#include "tokenize.h" // Tokenizer
|
2010-04-13 19:25:08 +02:00
|
|
|
|
|
|
|
#include "check.h"
|
2010-07-19 14:05:44 +02:00
|
|
|
#include "path.h"
|
2010-04-13 19:25:08 +02:00
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <fstream>
|
2012-04-08 14:18:13 +02:00
|
|
|
#include <sstream>
|
2010-09-06 21:00:56 +02:00
|
|
|
#include <stdexcept>
|
2010-08-31 22:18:07 +02:00
|
|
|
#include "timer.h"
|
2014-01-04 10:41:13 +01:00
|
|
|
#include "version.h"
|
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)
|
2013-05-11 11:35:04 +02:00
|
|
|
: _errorLogger(errorLogger), exitcode(0), _useGlobalSuppressions(useGlobalSuppressions), tooManyConfigs(false), _simplify(true)
|
2010-04-13 19:25:08 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CppCheck::~CppCheck()
|
|
|
|
{
|
2014-11-15 10:43:49 +01:00
|
|
|
while (!fileInfo.empty()) {
|
|
|
|
delete fileInfo.back();
|
|
|
|
fileInfo.pop_back();
|
|
|
|
}
|
2016-01-03 16:18:17 +01:00
|
|
|
S_timerResults.ShowResults(_settings.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
|
|
|
{
|
2014-10-03 10:40:48 +02:00
|
|
|
std::ifstream fin(path.c_str());
|
|
|
|
return processFile(path, 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);
|
|
|
|
return processFile(path, iss);
|
2010-04-13 19:25:08 +02:00
|
|
|
}
|
|
|
|
|
2014-10-03 10:40:48 +02:00
|
|
|
unsigned int CppCheck::processFile(const std::string& filename, std::istream& fileStream)
|
2010-04-13 19:25:08 +02:00
|
|
|
{
|
|
|
|
exitcode = 0;
|
|
|
|
|
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))
|
2012-01-06 16:08:08 +01:00
|
|
|
_settings.debugwarnings = false;
|
|
|
|
|
2011-04-24 18:10:25 +02:00
|
|
|
if (_settings.terminated())
|
|
|
|
return exitcode;
|
|
|
|
|
2015-07-25 17:39:44 +02:00
|
|
|
if (_settings.quiet == false) {
|
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);
|
|
|
|
_errorLogger.reportOut(std::string("Checking ") + fixedpath + std::string("..."));
|
|
|
|
}
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2015-05-25 21:15:55 +02:00
|
|
|
bool internalErrorFound(false);
|
2011-10-13 20:53:06 +02:00
|
|
|
try {
|
2015-07-24 13:30:41 +02:00
|
|
|
Preprocessor preprocessor(_settings, this);
|
2011-04-24 18:10:25 +02:00
|
|
|
std::list<std::string> configurations;
|
2015-05-25 21:15:55 +02:00
|
|
|
std::string filedata;
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2014-10-03 10:40:48 +02:00
|
|
|
{
|
2016-01-03 16:18:17 +01:00
|
|
|
Timer t("Preprocessor::preprocess", _settings.showtime, &S_timerResults);
|
|
|
|
preprocessor.preprocess(fileStream, filedata, configurations, filename, _settings.includePaths);
|
2010-07-19 14:05:44 +02:00
|
|
|
}
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2013-08-31 18:38:52 +02:00
|
|
|
if (_settings.checkConfiguration) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-12-11 10:22:06 +01:00
|
|
|
// Run define rules on raw code
|
2015-10-09 21:56:19 +02:00
|
|
|
for (std::list<Settings::Rule>::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) {
|
|
|
|
if (it->tokenlist == "define") {
|
2013-07-12 16:09:00 +02:00
|
|
|
Tokenizer tokenizer2(&_settings, this);
|
|
|
|
std::istringstream istr2(filedata);
|
|
|
|
tokenizer2.list.createTokens(istr2, filename);
|
|
|
|
|
|
|
|
for (const Token *tok = tokenizer2.list.front(); tok; tok = tok->next()) {
|
|
|
|
if (tok->str() == "#define") {
|
|
|
|
std::string code = std::string(tok->linenr()-1U, '\n');
|
|
|
|
for (const Token *tok2 = tok; tok2 && tok2->linenr() == tok->linenr(); tok2 = tok2->next())
|
|
|
|
code += " " + tok2->str();
|
|
|
|
Tokenizer tokenizer3(&_settings, this);
|
|
|
|
std::istringstream istr3(code);
|
|
|
|
tokenizer3.list.createTokens(istr3, tokenizer2.list.file(tok));
|
|
|
|
executeRules("define", tokenizer3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-03 16:18:17 +01:00
|
|
|
if (!_settings.userDefines.empty() && _settings.maxConfigs==1U) {
|
2011-04-24 18:10:25 +02:00
|
|
|
configurations.clear();
|
|
|
|
configurations.push_back(_settings.userDefines);
|
|
|
|
}
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2016-01-03 16:18:17 +01:00
|
|
|
if (!_settings.force && configurations.size() > _settings.maxConfigs) {
|
2012-12-26 18:35:49 +01:00
|
|
|
if (_settings.isEnabled("information")) {
|
|
|
|
tooManyConfigsError(Path::toNativeSeparators(filename),configurations.size());
|
|
|
|
} else {
|
|
|
|
tooManyConfigs = true;
|
|
|
|
}
|
2012-05-09 18:54:43 +02:00
|
|
|
}
|
|
|
|
|
2015-12-14 09:37:26 +01:00
|
|
|
// write dump file xml prolog
|
|
|
|
std::ofstream fdump;
|
|
|
|
if (_settings.dump) {
|
|
|
|
const std::string dumpfile(filename + ".dump");
|
|
|
|
fdump.open(dumpfile.c_str());
|
|
|
|
if (fdump.is_open()) {
|
|
|
|
fdump << "<?xml version=\"1.0\"?>" << std::endl;
|
|
|
|
fdump << "<dumps>" << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
2011-10-13 20:53:06 +02:00
|
|
|
for (std::list<std::string>::const_iterator it = configurations.begin(); it != configurations.end(); ++it) {
|
2015-12-11 10:22:06 +01:00
|
|
|
// bail out if terminated
|
|
|
|
if (_settings.terminated())
|
|
|
|
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.
|
2016-01-03 16:18:17 +01:00
|
|
|
if (!_settings.force && ++checkCount > _settings.maxConfigs)
|
2011-04-24 18:10:25 +02:00
|
|
|
break;
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2011-04-24 18:10:25 +02:00
|
|
|
cfg = *it;
|
2010-08-07 13:08:36 +02:00
|
|
|
|
2011-04-24 18:10:25 +02:00
|
|
|
// If only errors are printed, print filename after the check
|
2015-07-25 17:39:44 +02:00
|
|
|
if (_settings.quiet == false && it != configurations.begin()) {
|
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);
|
2014-10-03 10:02:46 +02:00
|
|
|
_errorLogger.reportOut("Checking " + fixedpath + ": " + cfg + "...");
|
2010-05-16 07:38:29 +02:00
|
|
|
}
|
|
|
|
|
2013-06-08 16:46:54 +02:00
|
|
|
if (!_settings.userDefines.empty()) {
|
|
|
|
if (!cfg.empty())
|
|
|
|
cfg = ";" + cfg;
|
|
|
|
cfg = _settings.userDefines + cfg;
|
|
|
|
}
|
|
|
|
|
2016-01-03 16:18:17 +01:00
|
|
|
Timer t("Preprocessor::getcode", _settings.showtime, &S_timerResults);
|
2014-10-02 19:40:41 +02:00
|
|
|
std::string codeWithoutCfg = preprocessor.getcode(filedata, cfg, filename);
|
2012-07-10 20:29:04 +02:00
|
|
|
t.Stop();
|
|
|
|
|
2014-10-02 19:40:41 +02:00
|
|
|
codeWithoutCfg += _settings.append();
|
2010-04-15 22:45:38 +02:00
|
|
|
|
2016-01-02 11:48:36 +01:00
|
|
|
if (_settings.preprocessOnly) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-12-11 10:22:06 +01:00
|
|
|
Tokenizer _tokenizer(&_settings, this);
|
2016-01-03 16:18:17 +01:00
|
|
|
if (_settings.showtime != SHOWTIME_NONE)
|
2015-12-11 10:22:06 +01:00
|
|
|
_tokenizer.setTimerResults(&S_timerResults);
|
|
|
|
|
|
|
|
try {
|
|
|
|
// Create tokens, skip rest of iteration if failed
|
|
|
|
std::istringstream istr(codeWithoutCfg);
|
2016-01-03 16:18:17 +01:00
|
|
|
Timer timer("Tokenizer::createTokens", _settings.showtime, &S_timerResults);
|
2015-12-11 10:22:06 +01:00
|
|
|
bool result = _tokenizer.createTokens(istr, filename.c_str());
|
|
|
|
timer.Stop();
|
|
|
|
if (!result)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// skip rest of iteration if just checking configuration
|
|
|
|
if (_settings.checkConfiguration)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Check raw tokens
|
|
|
|
checkRawTokens(_tokenizer);
|
|
|
|
|
|
|
|
// Simplify tokens into normal form, skip rest of iteration if failed
|
2016-01-03 16:18:17 +01:00
|
|
|
Timer timer2("Tokenizer::simplifyTokens1", _settings.showtime, &S_timerResults);
|
2015-12-11 10:22:06 +01:00
|
|
|
result = _tokenizer.simplifyTokens1(cfg);
|
|
|
|
timer2.Stop();
|
|
|
|
if (!result)
|
|
|
|
continue;
|
|
|
|
|
2015-12-14 09:37:26 +01:00
|
|
|
// dump xml if --dump
|
2015-12-14 20:05:17 +01:00
|
|
|
if (_settings.dump && fdump.is_open()) {
|
|
|
|
fdump << "<dump cfg=\"" << cfg << "\">" << std::endl;
|
2015-12-07 19:54:41 +01:00
|
|
|
preprocessor.dump(fdump);
|
2015-12-14 20:05:17 +01:00
|
|
|
_tokenizer.dump(fdump);
|
|
|
|
fdump << "</dump>" << std::endl;
|
2015-12-11 10:22:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Skip if we already met the same simplified token list
|
2016-01-03 16:18:17 +01:00
|
|
|
if (_settings.force || _settings.maxConfigs > 1) {
|
2015-12-11 10:22:06 +01:00
|
|
|
const unsigned long long checksum = _tokenizer.list.calculateChecksum();
|
|
|
|
if (checksums.find(checksum) != checksums.end())
|
|
|
|
continue;
|
|
|
|
checksums.insert(checksum);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check normal tokens
|
|
|
|
checkNormalTokens(_tokenizer);
|
|
|
|
|
|
|
|
// simplify more if required, skip rest of iteration if failed
|
|
|
|
if (_simplify) {
|
|
|
|
// if further simplification fails then skip rest of iteration
|
2016-01-03 16:18:17 +01:00
|
|
|
Timer timer3("Tokenizer::simplifyTokenList2", _settings.showtime, &S_timerResults);
|
2015-12-11 10:22:06 +01:00
|
|
|
result = _tokenizer.simplifyTokenList2();
|
|
|
|
timer3.Stop();
|
|
|
|
if (!result)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Check simplified tokens
|
|
|
|
checkSimplifiedTokens(_tokenizer);
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (const InternalError &e) {
|
2016-01-03 16:18:17 +01:00
|
|
|
if (_settings.isEnabled("information") && (_settings.debug || _settings.verbose))
|
2015-12-10 10:44:36 +01:00
|
|
|
purgedConfigurationMessage(filename, cfg);
|
2015-12-11 10:22:06 +01:00
|
|
|
internalErrorFound=true;
|
|
|
|
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
|
|
|
ErrorLogger::ErrorMessage::FileLocation loc;
|
|
|
|
if (e.token) {
|
|
|
|
loc.line = e.token->linenr();
|
|
|
|
const std::string fixedpath = Path::toNativeSeparators(_tokenizer.list.file(e.token));
|
|
|
|
loc.setfile(fixedpath);
|
|
|
|
} else {
|
|
|
|
ErrorLogger::ErrorMessage::FileLocation loc2;
|
|
|
|
loc2.setfile(Path::toNativeSeparators(filename.c_str()));
|
|
|
|
locationList.push_back(loc2);
|
|
|
|
loc.setfile(_tokenizer.list.getSourceFilePath());
|
|
|
|
}
|
|
|
|
locationList.push_back(loc);
|
|
|
|
const ErrorLogger::ErrorMessage errmsg(locationList,
|
|
|
|
Severity::error,
|
|
|
|
e.errorMessage,
|
|
|
|
e.id,
|
|
|
|
false);
|
|
|
|
|
|
|
|
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
|
|
|
|
2015-12-14 09:37:26 +01:00
|
|
|
// dumped all configs, close root </dumps> element now
|
|
|
|
if (_settings.dump && fdump.is_open())
|
|
|
|
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());
|
|
|
|
} catch (const InternalError &e) {
|
|
|
|
internalError(filename, e.errorMessage);
|
2015-05-25 21:15:55 +02:00
|
|
|
exitcode=1; // e.g. reflect a syntax error
|
2011-04-24 18:10:25 +02:00
|
|
|
}
|
|
|
|
|
2015-01-07 19:26:16 +01:00
|
|
|
// In jointSuppressionReport mode, unmatched suppressions are
|
|
|
|
// collected after all files are processed
|
|
|
|
if (!_settings.jointSuppressionReport && (_settings.isEnabled("information") || _settings.checkConfiguration)) {
|
|
|
|
reportUnmatchedSuppressions(_settings.nomsg.getUnmatchedLocalSuppressions(filename, unusedFunctionCheckIsEnabled()));
|
|
|
|
}
|
2010-04-13 19:25:08 +02:00
|
|
|
|
2011-07-25 13:25:09 +02:00
|
|
|
_errorList.clear();
|
2015-05-25 21:15:55 +02:00
|
|
|
if (internalErrorFound && (exitcode==0)) {
|
|
|
|
exitcode=1;
|
|
|
|
}
|
2011-07-25 13:25:09 +02:00
|
|
|
return exitcode;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
|
|
if (_settings.isEnabled("information")) {
|
|
|
|
const ErrorLogger::ErrorMessage::FileLocation loc1(filename, 0);
|
|
|
|
std::list<ErrorLogger::ErrorMessage::FileLocation> callstack;
|
|
|
|
callstack.push_back(loc1);
|
|
|
|
|
|
|
|
ErrorLogger::ErrorMessage errmsg(callstack,
|
|
|
|
Severity::information,
|
|
|
|
fullmsg,
|
|
|
|
"internalError",
|
|
|
|
false);
|
|
|
|
|
|
|
|
_errorLogger.reportErr(errmsg);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Report on stdout
|
|
|
|
_errorLogger.reportOut(fullmsg);
|
|
|
|
}
|
|
|
|
}
|
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) {
|
|
|
|
if (_settings.terminated())
|
|
|
|
return;
|
2013-06-09 14:58:56 +02:00
|
|
|
|
2016-02-11 16:10:52 +01:00
|
|
|
if (tokenizer.isMaxTime())
|
|
|
|
return;
|
|
|
|
|
2016-01-03 16:18:17 +01:00
|
|
|
Timer timerRunChecks((*it)->name() + "::runChecks", _settings.showtime, &S_timerResults);
|
2015-12-11 10:22:06 +01:00
|
|
|
(*it)->runChecks(&tokenizer, &_settings, this);
|
|
|
|
}
|
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) {
|
|
|
|
Check::FileInfo *fi = (*it)->getFileInfo(&tokenizer, &_settings);
|
|
|
|
if (fi != nullptr)
|
|
|
|
fileInfo.push_back(fi);
|
|
|
|
}
|
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) {
|
2013-07-24 13:06:59 +02:00
|
|
|
if (_settings.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;
|
|
|
|
|
2016-01-03 16:18:17 +01:00
|
|
|
Timer timerSimpleChecks((*it)->name() + "::runSimplifiedChecks", _settings.showtime, &S_timerResults);
|
2015-12-11 10:22:06 +01:00
|
|
|
(*it)->runSimplifiedChecks(&tokenizer, &_settings, this);
|
|
|
|
timerSimpleChecks.Stop();
|
2011-11-20 23:41:26 +01:00
|
|
|
}
|
2015-12-11 10:22:06 +01:00
|
|
|
|
|
|
|
if (!_settings.terminated())
|
|
|
|
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;
|
2015-10-09 21:56:19 +02:00
|
|
|
for (std::list<Settings::Rule>::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) {
|
|
|
|
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());
|
|
|
|
|
2015-10-09 21:56:19 +02:00
|
|
|
for (std::list<Settings::Rule>::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) {
|
|
|
|
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>(),
|
|
|
|
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;
|
2015-11-28 12:30:03 +01:00
|
|
|
const ErrorLogger::ErrorMessage errmsg(callStack, 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
|
|
|
{
|
|
|
|
return _settings;
|
|
|
|
}
|
|
|
|
|
2012-12-26 18:35:49 +01:00
|
|
|
void CppCheck::tooManyConfigsError(const std::string &file, const std::size_t numberOfConfigurations)
|
|
|
|
{
|
|
|
|
if (!_settings.isEnabled("information") && !tooManyConfigs)
|
|
|
|
return;
|
|
|
|
|
|
|
|
tooManyConfigs = false;
|
|
|
|
|
|
|
|
if (_settings.isEnabled("information") && file.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
std::list<ErrorLogger::ErrorMessage::FileLocation> loclist;
|
|
|
|
if (!file.empty()) {
|
|
|
|
ErrorLogger::ErrorMessage::FileLocation location;
|
|
|
|
location.setfile(file);
|
|
|
|
loclist.push_back(location);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ostringstream msg;
|
2016-01-03 16:18:17 +01:00
|
|
|
msg << "Too many #ifdef configurations - cppcheck only checks " << _settings.maxConfigs;
|
|
|
|
if (numberOfConfigurations > _settings.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,
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
|
|
|
|
tooManyConfigs = false;
|
|
|
|
|
|
|
|
if (_settings.isEnabled("information") && file.empty())
|
|
|
|
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,
|
|
|
|
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)
|
|
|
|
{
|
2013-10-20 14:09:10 +02:00
|
|
|
if (!_settings.library.reportErrors(msg.file0))
|
|
|
|
return;
|
|
|
|
|
2016-01-03 16:18:17 +01:00
|
|
|
const std::string errmsg = msg.toString(_settings.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
|
|
|
|
if (std::find(_errorList.begin(), _errorList.end(), errmsg) != _errorList.end())
|
|
|
|
return;
|
|
|
|
|
2010-04-13 19:25:08 +02:00
|
|
|
std::string file;
|
|
|
|
unsigned int line(0);
|
2011-10-13 20:53:06 +02:00
|
|
|
if (!msg._callStack.empty()) {
|
2010-12-15 21:39:46 +01:00
|
|
|
file = msg._callStack.back().getfile(false);
|
2010-04-13 19:25:08 +02:00
|
|
|
line = msg._callStack.back().line;
|
|
|
|
}
|
|
|
|
|
2011-10-13 20:53:06 +02:00
|
|
|
if (_useGlobalSuppressions) {
|
2011-02-16 02:12:15 +01:00
|
|
|
if (_settings.nomsg.isSuppressed(msg._id, file, line))
|
|
|
|
return;
|
2011-10-13 20:53:06 +02:00
|
|
|
} else {
|
2011-02-16 02:12:15 +01:00
|
|
|
if (_settings.nomsg.isSuppressedLocal(msg._id, file, line))
|
|
|
|
return;
|
|
|
|
}
|
2010-04-13 19:25:08 +02:00
|
|
|
|
|
|
|
if (!_settings.nofail.isSuppressed(msg._id, file, line))
|
|
|
|
exitcode = 1;
|
|
|
|
|
|
|
|
_errorList.push_back(errmsg);
|
2012-04-06 18:16:59 +02:00
|
|
|
|
2010-04-13 19:25:08 +02:00
|
|
|
_errorLogger.reportErr(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CppCheck::reportOut(const std::string &outmsg)
|
|
|
|
{
|
|
|
|
_errorLogger.reportOut(outmsg);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2010-08-08 08:45:37 +02:00
|
|
|
_errorLogger.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)
|
|
|
|
{
|
2012-07-10 20:29:04 +02:00
|
|
|
// Suppressing info message?
|
|
|
|
std::string file;
|
|
|
|
unsigned int line(0);
|
|
|
|
if (!msg._callStack.empty()) {
|
|
|
|
file = msg._callStack.back().getfile(false);
|
|
|
|
line = msg._callStack.back().line;
|
|
|
|
}
|
|
|
|
if (_useGlobalSuppressions) {
|
|
|
|
if (_settings.nomsg.isSuppressed(msg._id, file, line))
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
if (_settings.nomsg.isSuppressedLocal(msg._id, file, line))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-06-18 23:15:48 +02:00
|
|
|
_errorLogger.reportInfo(msg);
|
|
|
|
}
|
|
|
|
|
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()
|
|
|
|
{
|
2015-01-06 15:08:25 +01:00
|
|
|
Settings s(_settings);
|
|
|
|
s.addEnabled("warning");
|
|
|
|
s.addEnabled("style");
|
|
|
|
s.addEnabled("portability");
|
|
|
|
s.addEnabled("performance");
|
|
|
|
s.addEnabled("information");
|
|
|
|
|
2012-12-26 18:35:49 +01:00
|
|
|
tooManyConfigs = true;
|
|
|
|
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
|
|
|
|
|
|
|
void CppCheck::analyseWholeProgram()
|
|
|
|
{
|
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)
|
2015-06-28 17:54:48 +02:00
|
|
|
(*it)->analyseWholeProgram(fileInfo, _settings, *this);
|
2014-11-15 10:43:49 +01:00
|
|
|
}
|
|
|
|
|
2015-01-07 19:26:16 +01:00
|
|
|
bool CppCheck::unusedFunctionCheckIsEnabled() const
|
|
|
|
{
|
2016-01-03 16:18:17 +01:00
|
|
|
return (_settings.jobs == 1 && _settings.isEnabled("unusedFunction"));
|
2015-01-07 19:26:16 +01:00
|
|
|
}
|