diff --git a/Makefile b/Makefile
index e04b0acdb..55ff9ba17 100644
--- a/Makefile
+++ b/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)
diff --git a/cppcheck.cbp b/cppcheck.cbp
index c17789ed4..ccb1c5d78 100644
--- a/cppcheck.cbp
+++ b/cppcheck.cbp
@@ -35,10 +35,6 @@
-
-
-
-
@@ -47,6 +43,8 @@
+
+
@@ -64,13 +62,13 @@
-
-
+
+
@@ -85,17 +83,13 @@
+
+
-
-
-
-
-
-
@@ -112,20 +106,24 @@
+
+
+
+
+
+
-
-
-
-
+
+
@@ -140,19 +138,14 @@
-
+
+
-
-
-
-
-
-
@@ -161,6 +154,9 @@
+
+
+
@@ -173,14 +169,16 @@
+
+
+
-
@@ -189,6 +187,7 @@
+
@@ -197,10 +196,7 @@
-
-
-
@@ -215,12 +211,6 @@
-
-
-
-
-
-
diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp
index 8bec6e724..c79923706 100644
--- a/lib/checkbufferoverrun.cpp
+++ b/lib/checkbufferoverrun.cpp
@@ -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
diff --git a/lib/checkbufferoverrun.h b/lib/checkbufferoverrun.h
index 93c2e39c6..7e6dba1cb 100644
--- a/lib/checkbufferoverrun.h
+++ b/lib/checkbufferoverrun.h
@@ -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 {
diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp
index 7e4717564..a03816c72 100644
--- a/lib/preprocessor.cpp
+++ b/lib/preprocessor.cpp
@@ -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 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 &incl
}
-std::string Preprocessor::handleIncludes(const std::string &code, const std::string &filePath, const std::list &includePaths, std::map &defs)
+std::string Preprocessor::handleIncludes(const std::string &code, const std::string &filePath, const std::list &includePaths, std::map &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..
diff --git a/lib/preprocessor.h b/lib/preprocessor.h
index 34b16a24b..a89d21552 100644
--- a/lib/preprocessor.h
+++ b/lib/preprocessor.h
@@ -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 &includePaths, std::map &defs);
+ std::string handleIncludes(const std::string &code, const std::string &filePath, const std::list &includePaths, std::map &defs);
private:
void missingInclude(const std::string &filename, unsigned int linenr, const std::string &header, bool userheader);
diff --git a/lib/token.cpp b/lib/token.cpp
index 9cb9453b8..fd42abb6a 100644
--- a/lib/token.cpp
+++ b/lib/token.cpp
@@ -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
diff --git a/lib/token.h b/lib/token.h
index 605c0f596..581911b27 100644
--- a/lib/token.h
+++ b/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;
};
/// @}
diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp
index 92cfca2ae..779dde147 100644
--- a/lib/tokenize.cpp
+++ b/lib/tokenize.cpp
@@ -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)
diff --git a/lib/tokenize.h b/lib/tokenize.h
index f7dad0fe1..389302580 100644
--- a/lib/tokenize.h
+++ b/lib/tokenize.h
@@ -728,33 +728,33 @@ private:
/** Token list */
Token *_tokens, *_tokensBack;
- /** sizeof information for known types */
- std::map _typeSize;
-
- /** filenames for the tokenized source code (source + included) */
- std::vector _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 _typeSize;
+
+ /** filenames for the tokenized source code (source + included) */
+ std::vector _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;
};
/// @}
diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp
index 4b0dc2f07..1e604fa47 100644
--- a/test/testbufferoverrun.cpp
+++ b/test/testbufferoverrun.cpp
@@ -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)
diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp
index c6c938e56..a156e616b 100644
--- a/test/testnullpointer.cpp
+++ b/test/testnullpointer.cpp
@@ -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)
diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp
index 3aa8323db..a2c5c66e1 100644
--- a/test/testpreprocessor.cpp
+++ b/test/testpreprocessor.cpp
@@ -2827,13 +2827,13 @@ private:
void handleIncludes_def() {
const std::string filePath("test.c");
const std::list includePaths;
- std::map defs;
+ std::map 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);
- }
- */
}
};
diff --git a/test/testtoken.cpp b/test/testtoken.cpp
index caca72443..7044538e5 100644
--- a/test/testtoken.cpp
+++ b/test/testtoken.cpp
@@ -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)
diff --git a/tools/dmake.cpp b/tools/dmake.cpp
index 96512250b..bf33dbc35 100644
--- a/tools/dmake.cpp
+++ b/tools/dmake.cpp
@@ -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 "