Merge branch 'master' of github.com:danmar/cppcheck
This commit is contained in:
commit
467840c6e1
2
Makefile
2
Makefile
|
@ -6,7 +6,7 @@ ifndef HAVE_RULES
|
|||
endif
|
||||
|
||||
ifndef CXXFLAGS
|
||||
CXXFLAGS=-Wall -Wextra -Wshadow -pedantic -Wno-long-long -Wfloat-equal -Wcast-qual -Woverloaded-virtual -Wsign-promo -Wabi -Winline -Wredundant-decls -Wpacked -Wmissing-format-attribute -Wmissing-declarations -D_GLIBCXX_DEBUG -g
|
||||
CXXFLAGS=-pedantic -Wall -Wextra -Wabi -Wcast-qual -Wfloat-equal -Winline -Wmissing-declarations -Wmissing-format-attribute -Wno-long-long -Woverloaded-virtual -Wpacked -Wredundant-decls -Wshadow -Wsign-promo -D_GLIBCXX_DEBUG -g
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_RULES),yes)
|
||||
|
|
56
cppcheck.cbp
56
cppcheck.cbp
|
@ -35,10 +35,6 @@
|
|||
<Unit filename="cli/cppcheckexecutor.h" />
|
||||
<Unit filename="cli/filelister.cpp" />
|
||||
<Unit filename="cli/filelister.h" />
|
||||
<Unit filename="cli/filelister_unix.cpp" />
|
||||
<Unit filename="cli/filelister_unix.h" />
|
||||
<Unit filename="cli/filelister_win32.cpp" />
|
||||
<Unit filename="cli/filelister_win32.h" />
|
||||
<Unit filename="cli/main.cpp" />
|
||||
<Unit filename="cli/pathmatch.cpp" />
|
||||
<Unit filename="cli/pathmatch.h" />
|
||||
|
@ -47,6 +43,8 @@
|
|||
<Unit filename="cli/threadexecutor.h" />
|
||||
<Unit filename="gui/aboutdialog.cpp" />
|
||||
<Unit filename="gui/aboutdialog.h" />
|
||||
<Unit filename="gui/application.cpp" />
|
||||
<Unit filename="gui/application.h" />
|
||||
<Unit filename="gui/applicationdialog.cpp" />
|
||||
<Unit filename="gui/applicationdialog.h" />
|
||||
<Unit filename="gui/applicationlist.cpp" />
|
||||
|
@ -64,13 +62,13 @@
|
|||
<Unit filename="gui/filelist.h" />
|
||||
<Unit filename="gui/fileviewdialog.cpp" />
|
||||
<Unit filename="gui/fileviewdialog.h" />
|
||||
<Unit filename="gui/helpwindow.cpp" />
|
||||
<Unit filename="gui/helpwindow.h" />
|
||||
<Unit filename="gui/logview.cpp" />
|
||||
<Unit filename="gui/logview.h" />
|
||||
<Unit filename="gui/main.cpp" />
|
||||
<Unit filename="gui/mainwindow.cpp" />
|
||||
<Unit filename="gui/mainwindow.h" />
|
||||
<Unit filename="gui/platforms.cpp" />
|
||||
<Unit filename="gui/platforms.h" />
|
||||
<Unit filename="gui/project.cpp" />
|
||||
<Unit filename="gui/project.h" />
|
||||
<Unit filename="gui/projectfile.cpp" />
|
||||
|
@ -85,17 +83,13 @@
|
|||
<Unit filename="gui/resultsview.h" />
|
||||
<Unit filename="gui/settingsdialog.cpp" />
|
||||
<Unit filename="gui/settingsdialog.h" />
|
||||
<Unit filename="gui/showtypes.cpp" />
|
||||
<Unit filename="gui/showtypes.h" />
|
||||
<Unit filename="gui/statsdialog.cpp" />
|
||||
<Unit filename="gui/statsdialog.h" />
|
||||
<Unit filename="gui/test.cpp" />
|
||||
<Unit filename="gui/test/main.cpp" />
|
||||
<Unit filename="gui/test/testtranslationhandler.cpp" />
|
||||
<Unit filename="gui/test/testtranslationhandler.h" />
|
||||
<Unit filename="gui/test/testxmlreport.cpp" />
|
||||
<Unit filename="gui/test/testxmlreport.h" />
|
||||
<Unit filename="gui/test/testxmlreportv1.cpp" />
|
||||
<Unit filename="gui/test/testxmlreportv1.h" />
|
||||
<Unit filename="gui/test/testxmlreportv2.cpp" />
|
||||
<Unit filename="gui/test/testxmlreportv2.h" />
|
||||
<Unit filename="gui/threadhandler.cpp" />
|
||||
<Unit filename="gui/threadhandler.h" />
|
||||
|
@ -112,20 +106,24 @@
|
|||
<Unit filename="gui/xmlreportv2.cpp" />
|
||||
<Unit filename="gui/xmlreportv2.h" />
|
||||
<Unit filename="lib/check.h" />
|
||||
<Unit filename="lib/check64bit.cpp" />
|
||||
<Unit filename="lib/check64bit.h" />
|
||||
<Unit filename="lib/checkassignif.cpp" />
|
||||
<Unit filename="lib/checkassignif.h" />
|
||||
<Unit filename="lib/checkautovariables.cpp" />
|
||||
<Unit filename="lib/checkautovariables.h" />
|
||||
<Unit filename="lib/checkboost.cpp" />
|
||||
<Unit filename="lib/checkboost.h" />
|
||||
<Unit filename="lib/checkbufferoverrun.cpp" />
|
||||
<Unit filename="lib/checkbufferoverrun.h" />
|
||||
<Unit filename="lib/checkclass.cpp" />
|
||||
<Unit filename="lib/checkclass.h" />
|
||||
<Unit filename="lib/checkdangerousfunctions.cpp" />
|
||||
<Unit filename="lib/checkdangerousfunctions.h" />
|
||||
<Unit filename="lib/checkexceptionsafety.cpp" />
|
||||
<Unit filename="lib/checkexceptionsafety.h" />
|
||||
<Unit filename="lib/checkheaders.cpp" />
|
||||
<Unit filename="lib/checkheaders.h" />
|
||||
<Unit filename="lib/checkmemoryleak.cpp" />
|
||||
<Unit filename="lib/checkmemoryleak.h" />
|
||||
<Unit filename="lib/checknonreentrantfunctions.cpp" />
|
||||
<Unit filename="lib/checknonreentrantfunctions.h" />
|
||||
<Unit filename="lib/checknullpointer.cpp" />
|
||||
<Unit filename="lib/checknullpointer.h" />
|
||||
<Unit filename="lib/checkobsoletefunctions.cpp" />
|
||||
|
@ -140,19 +138,14 @@
|
|||
<Unit filename="lib/checkuninitvar.h" />
|
||||
<Unit filename="lib/checkunusedfunctions.cpp" />
|
||||
<Unit filename="lib/checkunusedfunctions.h" />
|
||||
<Unit filename="lib/classinfo.h" />
|
||||
<Unit filename="lib/checkunusedvar.cpp" />
|
||||
<Unit filename="lib/checkunusedvar.h" />
|
||||
<Unit filename="lib/cppcheck.cpp" />
|
||||
<Unit filename="lib/cppcheck.h" />
|
||||
<Unit filename="lib/errorlogger.cpp" />
|
||||
<Unit filename="lib/errorlogger.h" />
|
||||
<Unit filename="lib/executionpath.cpp" />
|
||||
<Unit filename="lib/executionpath.h" />
|
||||
<Unit filename="lib/filelister.cpp" />
|
||||
<Unit filename="lib/filelister.h" />
|
||||
<Unit filename="lib/filelister_unix.cpp" />
|
||||
<Unit filename="lib/filelister_unix.h" />
|
||||
<Unit filename="lib/filelister_win32.cpp" />
|
||||
<Unit filename="lib/filelister_win32.h" />
|
||||
<Unit filename="lib/mathlib.cpp" />
|
||||
<Unit filename="lib/mathlib.h" />
|
||||
<Unit filename="lib/path.cpp" />
|
||||
|
@ -161,6 +154,9 @@
|
|||
<Unit filename="lib/preprocessor.h" />
|
||||
<Unit filename="lib/settings.cpp" />
|
||||
<Unit filename="lib/settings.h" />
|
||||
<Unit filename="lib/standards.h" />
|
||||
<Unit filename="lib/suppressions.cpp" />
|
||||
<Unit filename="lib/suppressions.h" />
|
||||
<Unit filename="lib/symboldatabase.cpp" />
|
||||
<Unit filename="lib/symboldatabase.h" />
|
||||
<Unit filename="lib/timer.cpp" />
|
||||
|
@ -173,14 +169,16 @@
|
|||
<Unit filename="test/options.h" />
|
||||
<Unit filename="test/redirect.h" />
|
||||
<Unit filename="test/test.cxx" />
|
||||
<Unit filename="test/test64bit.cpp" />
|
||||
<Unit filename="test/testassignif.cpp" />
|
||||
<Unit filename="test/testautovariables.cpp" />
|
||||
<Unit filename="test/testboost.cpp" />
|
||||
<Unit filename="test/testbufferoverrun.cpp" />
|
||||
<Unit filename="test/testcharvar.cpp" />
|
||||
<Unit filename="test/testclass.cpp" />
|
||||
<Unit filename="test/testcmdlineparser.cpp" />
|
||||
<Unit filename="test/testconstructors.cpp" />
|
||||
<Unit filename="test/testcppcheck.cpp" />
|
||||
<Unit filename="test/testdangerousfunctions.cpp" />
|
||||
<Unit filename="test/testdivision.cpp" />
|
||||
<Unit filename="test/testerrorlogger.cpp" />
|
||||
<Unit filename="test/testexceptionsafety.cpp" />
|
||||
|
@ -189,6 +187,7 @@
|
|||
<Unit filename="test/testincompletestatement.cpp" />
|
||||
<Unit filename="test/testmathlib.cpp" />
|
||||
<Unit filename="test/testmemleak.cpp" />
|
||||
<Unit filename="test/testnonreentrantfunctions.cpp" />
|
||||
<Unit filename="test/testnullpointer.cpp" />
|
||||
<Unit filename="test/testobsoletefunctions.cpp" />
|
||||
<Unit filename="test/testoptions.cpp" />
|
||||
|
@ -197,10 +196,7 @@
|
|||
<Unit filename="test/testpathmatch.cpp" />
|
||||
<Unit filename="test/testpostfixoperator.cpp" />
|
||||
<Unit filename="test/testpreprocessor.cpp" />
|
||||
<Unit filename="test/testredundantif.cpp" />
|
||||
<Unit filename="test/testrunner.cpp" />
|
||||
<Unit filename="test/testsecurity.cpp" />
|
||||
<Unit filename="test/testsettings.cpp" />
|
||||
<Unit filename="test/testsimplifytokens.cpp" />
|
||||
<Unit filename="test/teststl.cpp" />
|
||||
<Unit filename="test/testsuite.cpp" />
|
||||
|
@ -215,12 +211,6 @@
|
|||
<Unit filename="test/testunusedprivfunc.cpp" />
|
||||
<Unit filename="test/testunusedvar.cpp" />
|
||||
<Unit filename="test/testutils.h" />
|
||||
<Unit filename="test/tinyxml/tinystr.cpp" />
|
||||
<Unit filename="test/tinyxml/tinystr.h" />
|
||||
<Unit filename="test/tinyxml/tinyxml.cpp" />
|
||||
<Unit filename="test/tinyxml/tinyxml.h" />
|
||||
<Unit filename="test/tinyxml/tinyxmlerror.cpp" />
|
||||
<Unit filename="test/tinyxml/tinyxmlparser.cpp" />
|
||||
<Unit filename="tools/dmake.cpp" />
|
||||
<Unit filename="tools/extracttests.cpp" />
|
||||
<Extensions>
|
||||
|
|
|
@ -107,10 +107,10 @@ void CheckBufferOverrun::possibleBufferOverrunError(const Token *tok, const std:
|
|||
"The source buffer is larger than the destination buffer so there is the potential for overflowing the destination buffer.");
|
||||
}
|
||||
|
||||
void CheckBufferOverrun::possibleReadlinkBufferOverrunError(const Token* tok, const std::string &varname)
|
||||
void CheckBufferOverrun::possibleReadlinkBufferOverrunError(const Token* tok, const std::string &funcname, const std::string &varname)
|
||||
{
|
||||
const std::string errmsg = "readlink() might return the full size of '" + varname + "'. Lower the supplied size by one.\n"
|
||||
"readlink() might return the full size of '" + varname + "'. Lower the supplied size by one. "
|
||||
const std::string errmsg = funcname + "() might return the full size of '" + varname + "'. Lower the supplied size by one.\n" +
|
||||
funcname + "() might return the full size of '" + varname + "'. Lower the supplied size by one. "
|
||||
"If a " + varname + "[len] = '\\0'; statement follows, it will overrun the buffer.";
|
||||
|
||||
reportInconclusiveError(tok, Severity::warning, "possibleReadlinkBufferOverrun", errmsg);
|
||||
|
@ -1192,29 +1192,12 @@ void CheckBufferOverrun::checkScope(const Token *tok, const ArrayInfo &arrayInfo
|
|||
outOfBoundsError(tok->tokAt(4), "snprintf size", true, n, total_size);
|
||||
}
|
||||
|
||||
// readlink()
|
||||
if (_settings->standards.posix && Token::Match(tok, "readlink ( %any% , %varid% , %num% )", arrayInfo.varid())) {
|
||||
const MathLib::bigint n = MathLib::toLongNumber(tok->strAt(6));
|
||||
if (total_size > 0 && n > total_size)
|
||||
outOfBoundsError(tok->tokAt(4), "readlink() buf size", true, n, total_size);
|
||||
|
||||
if (_settings->inconclusive) {
|
||||
// readlink() never terminates the buffer, check the end of the scope for buffer termination.
|
||||
bool found_termination = false;
|
||||
const Token *scope_end = scope_begin->link();
|
||||
for (const Token *tok2 = tok->tokAt(8); tok2 && tok2 != scope_end; tok2 = tok2->next()) {
|
||||
if (Token::Match(tok2, "%varid% [ %any% ] = 0 ;", tok->tokAt(4)->varId())) {
|
||||
found_termination = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_termination) {
|
||||
bufferNotZeroTerminatedError(tok, tok->tokAt(4)->str(), "readlink");
|
||||
} else if (n == total_size) {
|
||||
possibleReadlinkBufferOverrunError(tok, tok->tokAt(4)->str());
|
||||
}
|
||||
}
|
||||
// readlink() / readlinkat() buffer usage
|
||||
if (_settings->standards.posix) {
|
||||
if (Token::Match(tok, "readlink ( %any% , %varid% , %num% )", arrayInfo.varid()))
|
||||
checkReadlinkBufferUsage(tok, scope_begin, total_size, false);
|
||||
else if (Token::Match(tok, "readlinkat ( %any , %any% , %varid% , %num% )", arrayInfo.varid()))
|
||||
checkReadlinkBufferUsage(tok, scope_begin, total_size, true);
|
||||
}
|
||||
|
||||
// undefined behaviour: result of pointer arithmetic is out of bounds
|
||||
|
@ -1227,6 +1210,34 @@ void CheckBufferOverrun::checkScope(const Token *tok, const ArrayInfo &arrayInfo
|
|||
}
|
||||
}
|
||||
|
||||
void CheckBufferOverrun::checkReadlinkBufferUsage(const Token* tok, const Token *scope_begin, const MathLib::bigint total_size, const bool is_readlinkat)
|
||||
{
|
||||
unsigned int param_offset = is_readlinkat ? 2 : 0;
|
||||
const std::string funcname = is_readlinkat ? "readlinkat" : "readlink";
|
||||
|
||||
const MathLib::bigint n = MathLib::toLongNumber(tok->strAt(6 + param_offset));
|
||||
if (total_size > 0 && n > total_size)
|
||||
outOfBoundsError(tok->tokAt(4 + param_offset), funcname + "() buf size", true, n, total_size);
|
||||
|
||||
if (!_settings->inconclusive)
|
||||
return;
|
||||
|
||||
// readlink()/readlinkat() never terminates the buffer, check the end of the scope for buffer termination.
|
||||
bool found_termination = false;
|
||||
const Token *scope_end = scope_begin->link();
|
||||
for (const Token *tok2 = tok->tokAt(8 + param_offset); tok2 && tok2 != scope_end; tok2 = tok2->next()) {
|
||||
if (Token::Match(tok2, "%varid% [ %any% ] = 0 ;", tok->tokAt(4 + param_offset)->varId())) {
|
||||
found_termination = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_termination) {
|
||||
bufferNotZeroTerminatedError(tok, tok->tokAt(4 + param_offset)->str(), funcname);
|
||||
} else if (n == total_size) {
|
||||
possibleReadlinkBufferOverrunError(tok, funcname, tok->tokAt(4 + param_offset)->str());
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Checking local variables in a scope
|
||||
|
|
|
@ -195,6 +195,9 @@ public:
|
|||
/** Helper function used when parsing for-loops */
|
||||
void parse_for_body(const Token *tok2, const ArrayInfo &arrayInfo, const std::string &strindex, bool condition_out_of_bounds, unsigned int counter_varid, const std::string &min_counter_value, const std::string &max_counter_value);
|
||||
|
||||
/** Check readlink or readlinkat() buffer usage */
|
||||
void checkReadlinkBufferUsage(const Token *tok, const Token *scope_begin, const MathLib::bigint total_size, const bool is_readlinkat);
|
||||
|
||||
/**
|
||||
* Helper function for checkFunctionCall - check a function parameter
|
||||
* \param tok token for the function name
|
||||
|
@ -223,7 +226,7 @@ public:
|
|||
void pointerOutOfBoundsError(const Token *tok, const std::string &object); // UB when result of calculation is out of bounds
|
||||
void arrayIndexThenCheckError(const Token *tok, const std::string &indexName);
|
||||
void possibleBufferOverrunError(const Token *tok, const std::string &src, const std::string &dst, bool cat);
|
||||
void possibleReadlinkBufferOverrunError(const Token *tok, const std::string &varname);
|
||||
void possibleReadlinkBufferOverrunError(const Token *tok, const std::string &funcname, const std::string &varname);
|
||||
|
||||
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) {
|
||||
CheckBufferOverrun c(0, settings, errorLogger);
|
||||
|
@ -241,7 +244,7 @@ public:
|
|||
c.pointerOutOfBoundsError(0, "array");
|
||||
c.arrayIndexThenCheckError(0, "index");
|
||||
c.possibleBufferOverrunError(0, "source", "destination", false);
|
||||
c.possibleReadlinkBufferOverrunError(0, "buffer");
|
||||
c.possibleReadlinkBufferOverrunError(0, "readlink", "buffer");
|
||||
}
|
||||
|
||||
std::string myName() const {
|
||||
|
|
|
@ -854,13 +854,44 @@ void Preprocessor::preprocess(std::istream &srcCodeStream, std::string &processe
|
|||
processedFile = ostr.str();
|
||||
}
|
||||
|
||||
handleIncludes(processedFile, filename, includePaths);
|
||||
if (_settings && _settings->userDefines.compare(0,14,"CPPCHECK-TEST;") == 0) {
|
||||
std::map<std::string, std::string> defs;
|
||||
|
||||
processedFile = replaceIfDefined(processedFile);
|
||||
// TODO: break out this code. There is other similar code.
|
||||
std::string::size_type pos1 = 0;
|
||||
while (pos1 != std::string::npos) {
|
||||
const std::string::size_type pos2 = _settings->userDefines.find_first_of(";=", pos1);
|
||||
const std::string::size_type pos3 = _settings->userDefines.find(";", pos1);
|
||||
|
||||
// Get all possible configurations..
|
||||
if (!_settings || (_settings && _settings->userDefines.empty()))
|
||||
resultConfigurations = getcfgs(processedFile, filename);
|
||||
std::string name, value;
|
||||
if (pos2 == std::string::npos)
|
||||
name = _settings->userDefines.substr(pos1);
|
||||
else
|
||||
name = _settings->userDefines.substr(pos1, pos2 - pos1);
|
||||
if (pos2 != pos3) {
|
||||
if (pos3 == std::string::npos)
|
||||
value = _settings->userDefines.substr(pos2+1);
|
||||
else
|
||||
value = _settings->userDefines.substr(pos2+1, pos3 - pos2 - 1);
|
||||
}
|
||||
|
||||
defs[name] = value;
|
||||
|
||||
pos1 = pos3;
|
||||
if (pos1 != std::string::npos)
|
||||
pos1++;
|
||||
}
|
||||
|
||||
processedFile = handleIncludes(processedFile, filename, includePaths, defs);
|
||||
} else {
|
||||
handleIncludes(processedFile, filename, includePaths);
|
||||
|
||||
processedFile = replaceIfDefined(processedFile);
|
||||
|
||||
// Get all possible configurations..
|
||||
if (!_settings || (_settings && _settings->userDefines.empty()))
|
||||
resultConfigurations = getcfgs(processedFile, filename);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1701,13 +1732,20 @@ static bool openHeader(std::string &filename, const std::list<std::string> &incl
|
|||
}
|
||||
|
||||
|
||||
std::string Preprocessor::handleIncludes(const std::string &code, const std::string &filePath, const std::list<std::string> &includePaths, std::map<std::string,int> &defs)
|
||||
std::string Preprocessor::handleIncludes(const std::string &code, const std::string &filePath, const std::list<std::string> &includePaths, std::map<std::string,std::string> &defs)
|
||||
{
|
||||
const std::string path(filePath.substr(0, 1 + filePath.find_last_of("\\/")));
|
||||
|
||||
// current #if indent level.
|
||||
unsigned int indent = 0;
|
||||
|
||||
// how deep does the #if match? this can never be bigger than "indent".
|
||||
unsigned int indentmatch = 0;
|
||||
|
||||
// has there been a true #if condition at the current indentmatch level?
|
||||
// then no more #elif or #else can be true before the #endif is seen.
|
||||
bool elseIsTrue = true;
|
||||
|
||||
std::ostringstream ostr;
|
||||
std::istringstream istr(code);
|
||||
std::string line;
|
||||
|
@ -1728,46 +1766,74 @@ std::string Preprocessor::handleIncludes(const std::string &code, const std::str
|
|||
continue;
|
||||
}
|
||||
|
||||
ostr << "#file " << filename << "\n"
|
||||
ostr << "#file \"" << filename << "\"\n"
|
||||
<< handleIncludes(read(fin, filename, NULL), filename, includePaths, defs) << std::endl
|
||||
<< "#endfile";
|
||||
} else if (line.compare(0,7,"#ifdef ") == 0) {
|
||||
if (indent == indentmatch && defs.find(getdef(line,true)) != defs.end())
|
||||
if (indent == indentmatch && defs.find(getdef(line,true)) != defs.end()) {
|
||||
elseIsTrue = false;
|
||||
indentmatch++;
|
||||
}
|
||||
++indent;
|
||||
|
||||
if (indent == indentmatch + 1)
|
||||
elseIsTrue = true;
|
||||
} else if (line.compare(0,8,"#ifndef ") == 0) {
|
||||
if (indent == indentmatch && defs.find(getdef(line,false)) == defs.end())
|
||||
if (indent == indentmatch && defs.find(getdef(line,false)) == defs.end()) {
|
||||
elseIsTrue = false;
|
||||
indentmatch++;
|
||||
}
|
||||
++indent;
|
||||
} else if (line.compare(0,5,"#else") == 0) {
|
||||
if (indentmatch == indent)
|
||||
indentmatch = indent - 1;
|
||||
else if (indentmatch == indent - 1)
|
||||
indentmatch = indent;
|
||||
|
||||
if (indent == indentmatch + 1)
|
||||
elseIsTrue = true;
|
||||
} else if (line.compare(0,4,"#if ") == 0) {
|
||||
if (indent == indentmatch && match_cfg_def(defs, line.substr(4))) {
|
||||
elseIsTrue = false;
|
||||
indentmatch++;
|
||||
}
|
||||
++indent;
|
||||
|
||||
if (indent == indentmatch + 1)
|
||||
elseIsTrue = true;
|
||||
} else if (line.compare(0,6,"#elif ") == 0 || line.compare(0,5,"#else") == 0) {
|
||||
if (!elseIsTrue) {
|
||||
if (indentmatch == indent)
|
||||
indentmatch = indent - 1;
|
||||
} else {
|
||||
if (indentmatch == indent)
|
||||
indentmatch = indent - 1;
|
||||
else if (indentmatch == indent - 1) {
|
||||
if (line.compare(0,5,"#else")==0 || match_cfg_def(defs,line.substr(6))) {
|
||||
indentmatch = indent;
|
||||
elseIsTrue = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (line == "#endif") {
|
||||
--indent;
|
||||
if (indentmatch > indent)
|
||||
if (indentmatch > indent) {
|
||||
indentmatch = indent;
|
||||
elseIsTrue = false;
|
||||
}
|
||||
} else if (indentmatch == indent) {
|
||||
if (line.compare(0,8,"#define ")==0) {
|
||||
// no value
|
||||
if (line.find_first_of("( ", 8) == std::string::npos)
|
||||
defs[line.substr(8)] = 1;
|
||||
defs[line.substr(8)] = "";
|
||||
|
||||
// define value
|
||||
else if (line.find("(") == std::string::npos) {
|
||||
const std::string::size_type pos = line.find(" ", 8);
|
||||
const std::string val(line.substr(pos + 1));
|
||||
int i;
|
||||
std::istringstream istr2(val);
|
||||
istr2 >> i;
|
||||
defs[line.substr(8,pos-8)] = i;
|
||||
defs[line.substr(8,pos-8)] = line.substr(pos+1);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
ostr << line;
|
||||
else if (line.compare(0,7,"#undef ") == 0) {
|
||||
defs.erase(line.substr(7));
|
||||
}
|
||||
|
||||
ostr << line;
|
||||
}
|
||||
|
||||
// A line has been read..
|
||||
|
|
|
@ -217,7 +217,7 @@ public:
|
|||
* @param defs defines (only values)
|
||||
* \return resulting string
|
||||
*/
|
||||
std::string handleIncludes(const std::string &code, const std::string &filePath, const std::list<std::string> &includePaths, std::map<std::string,int> &defs);
|
||||
std::string handleIncludes(const std::string &code, const std::string &filePath, const std::list<std::string> &includePaths, std::map<std::string,std::string> &defs);
|
||||
|
||||
private:
|
||||
void missingInclude(const std::string &filename, unsigned int linenr, const std::string &header, bool userheader);
|
||||
|
|
|
@ -30,7 +30,9 @@
|
|||
|
||||
Token::Token(Token **t) :
|
||||
tokensBack(t),
|
||||
_str(""),
|
||||
_next(0),
|
||||
_previous(0),
|
||||
_link(0),
|
||||
_isName(false),
|
||||
_isNumber(false),
|
||||
_isBoolean(false),
|
||||
|
@ -40,12 +42,10 @@ Token::Token(Token **t) :
|
|||
_isLong(false),
|
||||
_isUnused(false),
|
||||
_varId(0),
|
||||
_next(0),
|
||||
_previous(0),
|
||||
_link(0),
|
||||
_fileIndex(0),
|
||||
_linenr(0),
|
||||
_progressValue(0)
|
||||
_progressValue(0),
|
||||
_str("")
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -54,10 +54,8 @@ Token::~Token()
|
|||
|
||||
}
|
||||
|
||||
void Token::str(const std::string &s)
|
||||
void Token::update_property_info()
|
||||
{
|
||||
_str = s;
|
||||
|
||||
if (!_str.empty()) {
|
||||
_isName = bool(_str[0] == '_' || std::isalpha(_str[0]));
|
||||
|
||||
|
@ -72,15 +70,27 @@ void Token::str(const std::string &s)
|
|||
_isBoolean = true;
|
||||
else
|
||||
_isBoolean = false;
|
||||
} else {
|
||||
_isName = false;
|
||||
_isNumber = false;
|
||||
_isBoolean = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Token::str(const std::string &s)
|
||||
{
|
||||
_str = s;
|
||||
_varId = 0;
|
||||
|
||||
update_property_info();
|
||||
}
|
||||
|
||||
void Token::concatStr(std::string const& b)
|
||||
{
|
||||
_str.erase(_str.length() - 1);
|
||||
_str.append(b.begin() + 1, b.end());
|
||||
|
||||
update_property_info();
|
||||
}
|
||||
|
||||
std::string Token::strValue() const
|
||||
|
|
18
lib/token.h
18
lib/token.h
|
@ -48,6 +48,10 @@ public:
|
|||
|
||||
void str(const std::string &s);
|
||||
|
||||
/**
|
||||
* Concatenate two (quoted) strings. Automatically cuts of the last/first character.
|
||||
* Example: "hello ""world" -> "hello world". Used by the token simplifier.
|
||||
*/
|
||||
void concatStr(std::string const& b);
|
||||
|
||||
const std::string &str() const {
|
||||
|
@ -424,7 +428,10 @@ private:
|
|||
static int firstWordLen(const char *str);
|
||||
|
||||
|
||||
std::string _str;
|
||||
Token *_next;
|
||||
Token *_previous;
|
||||
Token *_link;
|
||||
|
||||
bool _isName;
|
||||
bool _isNumber;
|
||||
bool _isBoolean;
|
||||
|
@ -434,17 +441,20 @@ private:
|
|||
bool _isLong;
|
||||
bool _isUnused;
|
||||
unsigned int _varId;
|
||||
Token *_next;
|
||||
Token *_previous;
|
||||
Token *_link;
|
||||
unsigned int _fileIndex;
|
||||
unsigned int _linenr;
|
||||
|
||||
/** Updates internal property cache like _isName or _isBoolean.
|
||||
Called after any _str() modification. */
|
||||
void update_property_info();
|
||||
|
||||
/**
|
||||
* A value from 0-100 that provides a rough idea about where in the token
|
||||
* list this token is located.
|
||||
*/
|
||||
unsigned int _progressValue;
|
||||
|
||||
std::string _str;
|
||||
};
|
||||
|
||||
/// @}
|
||||
|
|
|
@ -42,41 +42,28 @@
|
|||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
Tokenizer::Tokenizer()
|
||||
: _settings(0), _errorLogger(0)
|
||||
Tokenizer::Tokenizer() :
|
||||
_tokens(0), //no tokens to start with
|
||||
_tokensBack(0),
|
||||
_settings(0),
|
||||
_errorLogger(0),
|
||||
_symbolDatabase(0),
|
||||
_varId(0),
|
||||
_codeWithTemplates(false) //is there any templates?
|
||||
{
|
||||
// No tokens to start with
|
||||
_tokens = 0;
|
||||
_tokensBack = 0;
|
||||
|
||||
// is there any templates?
|
||||
_codeWithTemplates = false;
|
||||
|
||||
// symbol database
|
||||
_symbolDatabase = NULL;
|
||||
|
||||
// variable count
|
||||
_varId = 0;
|
||||
}
|
||||
|
||||
Tokenizer::Tokenizer(const Settings *settings, ErrorLogger *errorLogger)
|
||||
: _settings(settings), _errorLogger(errorLogger)
|
||||
Tokenizer::Tokenizer(const Settings *settings, ErrorLogger *errorLogger) :
|
||||
_tokens(0), //no tokens to start with
|
||||
_tokensBack(0),
|
||||
_settings(settings),
|
||||
_errorLogger(errorLogger),
|
||||
_symbolDatabase(0),
|
||||
_varId(0),
|
||||
_codeWithTemplates(false) //is there any templates?
|
||||
{
|
||||
// make sure settings are specified
|
||||
assert(_settings);
|
||||
|
||||
// No tokens to start with
|
||||
_tokens = 0;
|
||||
_tokensBack = 0;
|
||||
|
||||
// is there any templates?
|
||||
_codeWithTemplates = false;
|
||||
|
||||
// symbol database
|
||||
_symbolDatabase = NULL;
|
||||
|
||||
// variable count
|
||||
_varId = 0;
|
||||
}
|
||||
|
||||
Tokenizer::~Tokenizer()
|
||||
|
@ -738,9 +725,9 @@ Token * Tokenizer::deleteInvalidTypedef(Token *typeDef)
|
|||
}
|
||||
|
||||
struct Space {
|
||||
bool isNamespace;
|
||||
std::string className;
|
||||
const Token * classEnd;
|
||||
bool isNamespace;
|
||||
};
|
||||
|
||||
static Token *splitDefinitionFromTypedef(Token *tok)
|
||||
|
|
|
@ -728,33 +728,33 @@ private:
|
|||
/** Token list */
|
||||
Token *_tokens, *_tokensBack;
|
||||
|
||||
/** sizeof information for known types */
|
||||
std::map<std::string, unsigned int> _typeSize;
|
||||
|
||||
/** filenames for the tokenized source code (source + included) */
|
||||
std::vector<std::string> _files;
|
||||
|
||||
/** settings */
|
||||
const Settings * _settings;
|
||||
|
||||
/** errorlogger */
|
||||
ErrorLogger * const _errorLogger;
|
||||
|
||||
/** Symbol database that all checks etc can use */
|
||||
mutable SymbolDatabase *_symbolDatabase;
|
||||
|
||||
/** E.g. "A" for code where "#ifdef A" is true. This is used to
|
||||
print additional information in error situations. */
|
||||
std::string _configuration;
|
||||
|
||||
/** sizeof information for known types */
|
||||
std::map<std::string, unsigned int> _typeSize;
|
||||
|
||||
/** filenames for the tokenized source code (source + included) */
|
||||
std::vector<std::string> _files;
|
||||
|
||||
/** variable count */
|
||||
unsigned int _varId;
|
||||
|
||||
/**
|
||||
* was there any templates? templates that are "unused" are
|
||||
* removed from the token list
|
||||
*/
|
||||
bool _codeWithTemplates;
|
||||
|
||||
/** Symbol database that all checks etc can use */
|
||||
mutable SymbolDatabase *_symbolDatabase;
|
||||
|
||||
/** variable count */
|
||||
unsigned int _varId;
|
||||
};
|
||||
|
||||
/// @}
|
||||
|
|
|
@ -236,6 +236,7 @@ private:
|
|||
|
||||
TEST_CASE(bufferNotZeroTerminated);
|
||||
TEST_CASE(readlink);
|
||||
TEST_CASE(readlinkat);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3480,6 +3481,56 @@ private:
|
|||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void readlinkat() {
|
||||
check("void f()\n"
|
||||
"{\n"
|
||||
" int dirfd = 42;\n"
|
||||
" char buf[255];\n"
|
||||
" ssize_t len = readlinkat(dirfd, path, buf, sizeof(buf)-1);\n"
|
||||
" printf(\"%s\n\", buf);\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:5]: (warning) The buffer 'buf' is not zero-terminated after the call to readlinkat().\n", errout.str());
|
||||
|
||||
check("void f()\n"
|
||||
"{\n"
|
||||
" int dirfd = 42;\n"
|
||||
" char buf[255];\n"
|
||||
" ssize_t len = readlinkat(dirfd, path, buf, sizeof(buf)-1);\n"
|
||||
" buf[len] = 0;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("void f()\n"
|
||||
"{\n"
|
||||
" int dirfd = 42;\n"
|
||||
" char buf[10];\n"
|
||||
" ssize_t len = readlinkat(dirf, path, buf, 255);\n"
|
||||
" buf[len] = 0;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) readlinkat() buf size is out of bounds: Supplied size 255 is larger than actual size of 10\n", errout.str());
|
||||
|
||||
check("void f()\n"
|
||||
"{\n"
|
||||
" int dirfd = 42;\n"
|
||||
" char buf[255];\n"
|
||||
" ssize_t len = readlinkat(dirfd, path, buf, sizeof(buf));\n"
|
||||
" buf[len] = 0;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:5]: (warning) readlinkat() might return the full size of 'buf'. Lower the supplied size by one.\n", errout.str());
|
||||
|
||||
check("void f()\n"
|
||||
"{\n"
|
||||
" int dirfd = 42;\n"
|
||||
" char buf[255];\n"
|
||||
" ssize_t len = readlinkat(dirfd, path, buf, sizeof(buf)-1);\n"
|
||||
" if (len == -1) {\n"
|
||||
" return;\n"
|
||||
" }\n"
|
||||
" buf[len] = 0;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestBufferOverrun)
|
||||
|
|
|
@ -53,6 +53,7 @@ private:
|
|||
TEST_CASE(snprintf_with_non_zero_size);
|
||||
TEST_CASE(printf_with_invalid_va_argument);
|
||||
TEST_CASE(scanf_with_invalid_va_argument);
|
||||
TEST_CASE(nullpointer_in_return);
|
||||
}
|
||||
|
||||
void check(const char code[], bool inconclusive = false, bool cpp11 = false) {
|
||||
|
@ -175,6 +176,19 @@ private:
|
|||
check(code, true);
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Possible null pointer dereference: tok - otherwise it is redundant to check if tok is null at line 3\n", errout.str());
|
||||
}
|
||||
|
||||
check("int foo(const Token *tok)\n"
|
||||
"{\n"
|
||||
" while (tok){;}\n"
|
||||
"}\n", true);
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("int foo(const Token *tok)\n"
|
||||
"{\n"
|
||||
" while (tok){;}\n"
|
||||
" char a[2] = {0,0};\n"
|
||||
"}\n", true);
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void nullpointer1() {
|
||||
|
@ -1479,6 +1493,20 @@ private:
|
|||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (error) Possible null pointer dereference: iVal\n", errout.str());
|
||||
}
|
||||
|
||||
void nullpointer_in_return() {
|
||||
check("int foo() {\n"
|
||||
" int* iVal = 0;\n"
|
||||
" if(g()) iVal = g();\n"
|
||||
" return iVal[0];\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:4]: (error) Possible null pointer dereference: iVal\n", errout.str());
|
||||
|
||||
check("int foo(int* iVal) {\n"
|
||||
" return iVal[0];\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestNullPointer)
|
||||
|
|
|
@ -2827,13 +2827,13 @@ private:
|
|||
void handleIncludes_def() {
|
||||
const std::string filePath("test.c");
|
||||
const std::list<std::string> includePaths;
|
||||
std::map<std::string,int> defs;
|
||||
std::map<std::string,std::string> defs;
|
||||
Preprocessor preprocessor;
|
||||
|
||||
// ifdef
|
||||
{
|
||||
defs.clear();
|
||||
defs["A"] = 1;
|
||||
defs["A"] = "";
|
||||
{
|
||||
const std::string code("#ifdef A\n123\n#endif\n");
|
||||
const std::string actual(preprocessor.handleIncludes(code,filePath,includePaths,defs));
|
||||
|
@ -2848,7 +2848,7 @@ private:
|
|||
// ifndef
|
||||
{
|
||||
defs.clear();
|
||||
defs["A"] = 1;
|
||||
defs["A"] = "";
|
||||
{
|
||||
const std::string code("#ifndef A\n123\n#endif\n");
|
||||
const std::string actual(preprocessor.handleIncludes(code,filePath,includePaths,defs));
|
||||
|
@ -2866,17 +2866,68 @@ private:
|
|||
const std::string code("#ifndef X\n#define X\n123\n#endif\n"
|
||||
"#ifndef X\n#define X\n123\n#endif\n");
|
||||
const std::string actual(preprocessor.handleIncludes(code,filePath,includePaths,defs));
|
||||
ASSERT_EQUALS("\n\n123\n\n" "\n\n\n\n", actual);
|
||||
ASSERT_EQUALS("\n#define X\n123\n\n" "\n\n\n\n", actual);
|
||||
}
|
||||
|
||||
// #define => #if
|
||||
{
|
||||
defs.clear();
|
||||
const std::string code("#define X 123\n"
|
||||
"#if X==123\n"
|
||||
"456\n"
|
||||
"#endif\n");
|
||||
const std::string actual(preprocessor.handleIncludes(code,filePath,includePaths,defs));
|
||||
ASSERT_EQUALS("#define X 123\n\n456\n\n", actual);
|
||||
}
|
||||
|
||||
// #elif
|
||||
{
|
||||
const std::string code("#if defined(A)\n"
|
||||
"1\n"
|
||||
"#elif defined(B)\n"
|
||||
"2\n"
|
||||
"#elif defined(C)\n"
|
||||
"3\n"
|
||||
"#else\n"
|
||||
"4\n"
|
||||
"#endif");
|
||||
{
|
||||
defs.clear();
|
||||
defs["A"] = "";
|
||||
defs["C"] = "";
|
||||
const std::string actual(preprocessor.handleIncludes(code,filePath,includePaths,defs));
|
||||
ASSERT_EQUALS("\n1\n\n\n\n\n\n\n\n", actual);
|
||||
}
|
||||
|
||||
{
|
||||
defs.clear();
|
||||
defs["B"] = "";
|
||||
const std::string actual(preprocessor.handleIncludes(code,filePath,includePaths,defs));
|
||||
ASSERT_EQUALS("\n\n\n2\n\n\n\n\n\n", actual);
|
||||
}
|
||||
|
||||
{
|
||||
defs.clear();
|
||||
const std::string actual(preprocessor.handleIncludes(code,filePath,includePaths,defs));
|
||||
ASSERT_EQUALS("\n\n\n\n\n\n\n4\n\n", actual);
|
||||
}
|
||||
}
|
||||
|
||||
// #undef
|
||||
{
|
||||
const std::string code("#ifndef X\n"
|
||||
"#define X\n"
|
||||
"123\n"
|
||||
"#endif\n");
|
||||
|
||||
defs.clear();
|
||||
const std::string actual1(preprocessor.handleIncludes(code,filePath,includePaths,defs));
|
||||
|
||||
defs.clear();
|
||||
const std::string actual(preprocessor.handleIncludes(code + "#undef X\n" + code, filePath, includePaths, defs));
|
||||
|
||||
ASSERT_EQUALS(actual1 + "#undef X\n" + actual1, actual);
|
||||
}
|
||||
/*
|
||||
// define X 123 - #if
|
||||
{
|
||||
defs.clear();
|
||||
const std::string code("#define X 123\n#if X==123\n456\n#endif\n");
|
||||
const std::string actual(preprocessor.handleIncludes(code,filePath,includePaths,defs));
|
||||
ASSERT_EQUALS("\n\n456\n\n", actual);
|
||||
}
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -46,6 +46,14 @@ private:
|
|||
TEST_CASE(matchNumeric);
|
||||
TEST_CASE(matchBoolean);
|
||||
TEST_CASE(matchOr);
|
||||
|
||||
TEST_CASE(updateProperties)
|
||||
TEST_CASE(updatePropertiesConcatStr)
|
||||
TEST_CASE(isNameGuarantees1)
|
||||
TEST_CASE(isNameGuarantees2)
|
||||
TEST_CASE(isNameGuarantees3)
|
||||
TEST_CASE(isNameGuarantees4)
|
||||
TEST_CASE(isNameGuarantees5)
|
||||
}
|
||||
|
||||
void nextprevious() {
|
||||
|
@ -253,6 +261,63 @@ private:
|
|||
givenACodeSampleToTokenize op("+");
|
||||
ASSERT_EQUALS(true, Token::Match(op.tokens(), "%op%"));
|
||||
}
|
||||
|
||||
void updateProperties() {
|
||||
Token tok(NULL);
|
||||
tok.str("foobar");
|
||||
|
||||
ASSERT_EQUALS(true, tok.isName());
|
||||
ASSERT_EQUALS(false, tok.isNumber());
|
||||
|
||||
tok.str("123456");
|
||||
|
||||
ASSERT_EQUALS(false, tok.isName());
|
||||
ASSERT_EQUALS(true, tok.isNumber());
|
||||
}
|
||||
|
||||
void updatePropertiesConcatStr() {
|
||||
Token tok(NULL);
|
||||
tok.str("true");
|
||||
|
||||
ASSERT_EQUALS(true, tok.isBoolean());
|
||||
|
||||
tok.concatStr("123");
|
||||
|
||||
ASSERT_EQUALS(false, tok.isBoolean());
|
||||
ASSERT_EQUALS("tru23", tok.str());
|
||||
}
|
||||
|
||||
void isNameGuarantees1() {
|
||||
Token tok(NULL);
|
||||
tok.str("Name");
|
||||
ASSERT_EQUALS(true, tok.isName());
|
||||
}
|
||||
|
||||
void isNameGuarantees2() {
|
||||
Token tok(NULL);
|
||||
tok.str("_name");
|
||||
ASSERT_EQUALS(true, tok.isName());
|
||||
}
|
||||
|
||||
void isNameGuarantees3() {
|
||||
Token tok(NULL);
|
||||
tok.str("_123");
|
||||
ASSERT_EQUALS(true, tok.isName());
|
||||
}
|
||||
|
||||
void isNameGuarantees4() {
|
||||
Token tok(NULL);
|
||||
tok.str("123456");
|
||||
ASSERT_EQUALS(false, tok.isName());
|
||||
ASSERT_EQUALS(true, tok.isNumber());
|
||||
}
|
||||
|
||||
void isNameGuarantees5() {
|
||||
Token tok(NULL);
|
||||
tok.str("a123456");
|
||||
ASSERT_EQUALS(true, tok.isName());
|
||||
ASSERT_EQUALS(false, tok.isNumber());
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestToken)
|
||||
|
|
|
@ -216,21 +216,22 @@ int main(int argc, char **argv)
|
|||
|
||||
// The _GLIBCXX_DEBUG doesn't work in cygwin
|
||||
makeConditionalVariable(fout, "CXXFLAGS",
|
||||
"-pedantic "
|
||||
"-Wall "
|
||||
"-Wextra "
|
||||
"-Wshadow "
|
||||
"-pedantic "
|
||||
"-Wno-long-long "
|
||||
"-Wfloat-equal "
|
||||
"-Wcast-qual "
|
||||
"-Woverloaded-virtual "
|
||||
"-Wsign-promo "
|
||||
"-Wabi "
|
||||
"-Wcast-qual "
|
||||
"-Wfloat-equal "
|
||||
"-Winline "
|
||||
"-Wredundant-decls "
|
||||
"-Wpacked "
|
||||
"-Wmissing-format-attribute "
|
||||
"-Wmissing-declarations "
|
||||
"-Wmissing-format-attribute "
|
||||
"-Wno-long-long "
|
||||
"-Woverloaded-virtual "
|
||||
"-Wpacked "
|
||||
"-Wredundant-decls "
|
||||
"-Wshadow "
|
||||
"-Wsign-promo "
|
||||
// "-Wunreachable-code "
|
||||
// "-Wsign-conversion "
|
||||
// "-Wconversion "
|
||||
"-D_GLIBCXX_DEBUG "
|
||||
|
|
Loading…
Reference in New Issue