Merge branch 'master' of github.com:danmar/cppcheck

This commit is contained in:
Daniel Marjamäki 2011-10-24 23:20:14 +02:00
commit 467840c6e1
15 changed files with 436 additions and 163 deletions

View File

@ -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)

View File

@ -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>

View File

@ -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

View File

@ -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 {

View File

@ -854,6 +854,36 @@ void Preprocessor::preprocess(std::istream &srcCodeStream, std::string &processe
processedFile = ostr.str();
}
if (_settings && _settings->userDefines.compare(0,14,"CPPCHECK-TEST;") == 0) {
std::map<std::string, std::string> defs;
// 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);
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);
@ -862,6 +892,7 @@ void Preprocessor::preprocess(std::istream &srcCodeStream, std::string &processe
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 (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 - 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..

View File

@ -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);

View File

@ -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

View File

@ -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;
};
/// @}

View File

@ -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)

View File

@ -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;
};
/// @}

View File

@ -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)

View File

@ -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)

View File

@ -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 X 123 - #if
// #define => #if
{
defs.clear();
const std::string code("#define X 123\n#if X==123\n456\n#endif\n");
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("\n\n456\n\n", actual);
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);
}
*/
}
};

View File

@ -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)

View File

@ -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 "