From a52b73f9f9f6fe92730a5bd3bad2fb5b90b1b35b Mon Sep 17 00:00:00 2001 From: Thomas Jarosch Date: Sun, 16 Oct 2011 08:09:57 +0200 Subject: [PATCH] Fix #3208 (Simplify pointer to standard type, C only) The symbol database is unavailable during token simplification and &data[0] might return something completely different for C++. Moved code_is_c() from checkOther to Tokenizer. --- lib/checkother.cpp | 22 ++++------------------ lib/checkother.h | 2 -- lib/tokenize.cpp | 33 +++++++++++++++++++++++++++++++++ lib/tokenize.h | 6 ++++++ test/testbufferoverrun.cpp | 13 +++++++++++-- test/testtokenize.cpp | 20 ++++++++++++++++++-- 6 files changed, 72 insertions(+), 24 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 6d9c764bc..5b0c8dea5 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -147,7 +147,7 @@ void CheckOther::clarifyCondition() tok2 = tok2->link(); else if (Token::Match(tok2, "<|<=|==|!=|>|>=")) { // This might be a template - if (!code_is_c() && Token::Match(tok2->previous(), "%var% <")) + if (!_tokenizer->code_is_c() && Token::Match(tok2->previous(), "%var% <")) break; clarifyConditionError(tok, tok->strAt(2) == "=", false); @@ -1163,7 +1163,7 @@ void CheckOther::checkComparisonOfBoolWithInt() std::map::const_iterator iVar = boolvars.find(varTok->varId()); if (iVar != boolvars.end() && iVar->second && // Variable has to be a boolean ((tok->tokAt(1)->str() != "==" && tok->tokAt(1)->str() != "!=") || - ((MathLib::toLongNumber(numTok->str()) != 0) && (!code_is_c() || MathLib::toLongNumber(numTok->str()) != 1)))) { // == 0 and != 0 are allowed, for C also == 1 and != 1 + ((MathLib::toLongNumber(numTok->str()) != 0) && (!_tokenizer->code_is_c() || MathLib::toLongNumber(numTok->str()) != 1)))) { // == 0 and != 0 are allowed, for C also == 1 and != 1 comparisonOfBoolWithIntError(varTok, numTok->str()); } } else if (Token::Match(tok, "%num% >|>=|==|!=|<=|< %var%")) { // Comparing number with variable @@ -1172,7 +1172,7 @@ void CheckOther::checkComparisonOfBoolWithInt() std::map::const_iterator iVar = boolvars.find(varTok->varId()); if (iVar != boolvars.end() && iVar->second && // Variable has to be a boolean ((tok->tokAt(1)->str() != "==" && tok->tokAt(1)->str() != "!=") || - ((MathLib::toLongNumber(numTok->str()) != 0) && (!code_is_c() || MathLib::toLongNumber(numTok->str()) != 1)))) { // == 0 and != 0 are allowed, for C also == 1 and != 1 + ((MathLib::toLongNumber(numTok->str()) != 0) && (!_tokenizer->code_is_c() || MathLib::toLongNumber(numTok->str()) != 1)))) { // == 0 and != 0 are allowed, for C also == 1 and != 1 comparisonOfBoolWithIntError(varTok, numTok->str()); } } else if (Token::Match(tok, "true|false >|>=|==|!=|<=|< %var%")) { // Comparing boolean constant with variable @@ -1899,24 +1899,10 @@ static bool isFunction(const std::string &name, const Token *startToken) return false; } -bool CheckOther::code_is_c() const -{ - const std::string fname = _tokenizer->getFiles()->at(0); - const size_t position = fname.rfind("."); - - if (position != std::string::npos) { - const std::string ext = fname.substr(position); - if (ext == ".c" || ext == ".C") - return true; - } - - return false; -} - void CheckOther::checkMisusedScopedObject() { // Skip this check for .c files - if (code_is_c()) { + if (_tokenizer->code_is_c()) { return; } diff --git a/lib/checkother.h b/lib/checkother.h index 97692fc37..e09776410 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -398,8 +398,6 @@ private: return varname; } - - bool code_is_c() const; }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index d2246f66d..1d2dc7aa1 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2338,6 +2338,9 @@ bool Tokenizer::tokenize(std::istream &code, // operator = => operator= simplifyOperatorName(); + // Simplify pointer to standard types (C only) + simplifyPointerToStandardType(); + // simplify function pointers simplifyFunctionPointers(); @@ -5390,6 +5393,22 @@ void Tokenizer::simplifyFunctionParameters() } } +void Tokenizer::simplifyPointerToStandardType() +{ + if (!code_is_c()) + return; + + for (Token *tok = _tokens; tok; tok = tok->next()) { + if (!Token::Match(tok, "& %var% [ 0 ]")) + continue; + + // Remove '[ 0 ]' suffix + tok->next()->eraseTokens(tok->next(), tok->tokAt(5)); + // Remove '&' prefix + tok = tok->previous(); + tok->deleteNext(); + } +} void Tokenizer:: simplifyFunctionPointers() { @@ -9599,3 +9618,17 @@ void Tokenizer::printUnknownTypes() _errorLogger->reportOut(ss.str()); } } + +bool Tokenizer::code_is_c() const +{ + const std::string fname = getFiles()->at(0); + const size_t position = fname.rfind("."); + + if (position != std::string::npos) { + const std::string ext = fname.substr(position); + if (ext == ".c" || ext == ".C") + return true; + } + + return false; +} diff --git a/lib/tokenize.h b/lib/tokenize.h index 0d2253478..45df417d2 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -514,6 +514,9 @@ public: */ void simplifyStd(); + /** Simplify pointer to standard type (C only) */ + void simplifyPointerToStandardType(); + /** Simplify function pointers */ void simplifyFunctionPointers(); @@ -711,6 +714,9 @@ public: */ void printUnknownTypes(); + /** Checks if the file extensions is .c or .C */ + bool code_is_c() const; + private: /** Disable copy constructor, no implementation */ Tokenizer(const Tokenizer &); diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 40823a370..2b1ab08b4 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -35,7 +35,7 @@ private: - void check(const char code[], bool experimental = true) { + void check(const char code[], bool experimental = true, const std::string &filename="test.cpp") { // Clear the error buffer.. errout.str(""); @@ -49,7 +49,7 @@ private: // Tokenize.. Tokenizer tokenizer(&settings, this); std::istringstream istr(code); - tokenizer.tokenize(istr, "test.cpp"); + tokenizer.tokenize(istr, filename.c_str()); // Assign variable ids tokenizer.simplifyTokenList(); @@ -3436,6 +3436,15 @@ private: "}\n"); ASSERT_EQUALS("[test.cpp:4]: (warning) The buffer 'buf' is not zero-terminated after the call to readlink().\n", errout.str()); + // C only: Primitive pointer simplification + check("void f()\n" + "{\n" + " char buf[255];\n" + " ssize_t len = readlink(path, &buf[0], sizeof(buf)-1);\n" + " printf(\"%s\n\", buf);\n" + "}\n", true, "test.c"); + ASSERT_EQUALS("[test.c:4]: (warning) The buffer 'buf' is not zero-terminated after the call to readlink().\n", errout.str()); + check("void f()\n" "{\n" " char buf[255];\n" diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 83b100d6b..889321ecc 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -286,6 +286,7 @@ private: TEST_CASE(simplifyConst); TEST_CASE(switchCase); + TEST_CASE(simplifyPointerToStandardType); TEST_CASE(functionpointer1); TEST_CASE(functionpointer2); TEST_CASE(functionpointer3); @@ -375,7 +376,7 @@ private: } - std::string tokenizeAndStringify(const char code[], bool simplify = false, bool expand = true, Settings::PlatformType platform = Settings::Unspecified) { + std::string tokenizeAndStringify(const char code[], bool simplify = false, bool expand = true, Settings::PlatformType platform = Settings::Unspecified, const std::string &filename="test.cpp") { errout.str(""); Settings settings; @@ -385,7 +386,7 @@ private: // tokenize.. Tokenizer tokenizer(&settings, this); std::istringstream istr(code); - tokenizer.tokenize(istr, "test.cpp"); + tokenizer.tokenize(istr, filename.c_str()); if (simplify) tokenizer.simplifyTokenList(); @@ -4669,6 +4670,21 @@ private: tokenizeAndStringify("void foo (int i) { switch(i) { case -1: break; } }")); } + void simplifyPointerToStandardType() { + // Pointer to standard type + ASSERT_EQUALS("char buf [ 100 ] ; readlink ( path , buf , 99 ) ;", + tokenizeAndStringify("char buf[100] ; readlink(path, &buf[0], 99);", + false, true, Settings::Unspecified, "test.c")); + + // Simplification of unknown type - C only + ASSERT_EQUALS("foo data [ 100 ] ; something ( foo ) ;", + tokenizeAndStringify("foo data[100]; something(&foo[0]);", false, true, Settings::Unspecified, "test.c")); + + // C++: No pointer simplification + ASSERT_EQUALS("foo data [ 100 ] ; something ( & foo [ 0 ] ) ;", + tokenizeAndStringify("foo data[100]; something(&foo[0]);")); + } + std::string simplifyFunctionPointers(const char code[]) { errout.str(""); Settings settings;