From 427c0f4bfd6259fd1fd313fc1f0c7eecf1473858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 2 Sep 2010 23:01:12 +0200 Subject: [PATCH] Fixed #1975 (segmentation fault of cppcheck) --- lib/preprocessor.cpp | 4 +- lib/tokenize.cpp | 184 ++++++++++++++++++++------------------ lib/tokenize.h | 5 +- test/testpreprocessor.cpp | 17 ++++ 4 files changed, 119 insertions(+), 91 deletions(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 33479eb89..8aaa473f8 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -919,7 +919,7 @@ std::list Preprocessor::getcfgs(const std::string &filedata, const { Tokenizer tokenizer(_settings, _errorLogger); std::istringstream tempIstr(s.c_str()); - if (!tokenizer.tokenize(tempIstr, filename.c_str())) + if (!tokenizer.tokenize(tempIstr, filename.c_str(), "", true)) { std::ostringstream lineStream; lineStream << __LINE__; @@ -1053,7 +1053,7 @@ void Preprocessor::simplifyCondition(const std::map &v { Tokenizer tokenizer; std::istringstream istr(("(" + condition + ")").c_str()); - tokenizer.tokenize(istr, ""); + tokenizer.tokenize(istr, "", "", true); if (Token::Match(tokenizer.tokens(), "( %var% )")) { diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 252f36355..59cb790b8 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -1695,7 +1695,10 @@ void Tokenizer::simplifyTypedef() } } -bool Tokenizer::tokenize(std::istream &code, const char FileName[], const std::string &configuration) +bool Tokenizer::tokenize(std::istream &code, + const char FileName[], + const std::string &configuration, + const bool preprocessorCondition) { _configuration = configuration; @@ -1704,7 +1707,6 @@ bool Tokenizer::tokenize(std::istream &code, const char FileName[], const std::s createTokens(code); - // remove inline SQL (Oracle PRO*C). Ticket: #1959 for (Token *tok = _tokens; tok; tok = tok->next()) { @@ -1816,105 +1818,108 @@ bool Tokenizer::tokenize(std::istream &code, const char FileName[], const std::s } // check for more complicated syntax errors when using templates.. - for (const Token *tok = _tokens; tok; tok = tok->next()) + if (!preprocessorCondition) { - // skip executing scopes.. - if (Token::Match(tok, ") const| {")) + for (const Token *tok = _tokens; tok; tok = tok->next()) { - while (tok->str() != "{") + // skip executing scopes.. + if (Token::Match(tok, ") const| {")) + { + while (tok->str() != "{") + tok = tok->next(); + tok = tok->link(); + } + + // skip executing scopes (ticket #1984).. + if (Token::simpleMatch(tok, "; {")) + { + tok = tok->next()->link(); + } + + // skip executing scopes (ticket #1985).. + if (Token::simpleMatch(tok, "try {")) + { + tok = tok->next()->link(); + while (Token::simpleMatch(tok, "} catch (")) + { + tok = tok->tokAt(2)->link(); + if (Token::simpleMatch(tok, ") {")) + tok = tok->next()->link(); + } + } + + // not start of statement? + if (tok->previous() && !Token::Match(tok, "[;{}]")) + continue; + + // skip starting tokens.. ;;; typedef typename foo::bar::.. + while (Token::Match(tok, "[;{}]")) tok = tok->next(); - tok = tok->link(); - } + while (Token::Match(tok, "typedef|typename")) + tok = tok->next(); + while (Token::Match(tok, "%type% ::")) + tok = tok->tokAt(2); + if (!tok) + break; - // skip executing scopes (ticket #1984).. - if (Token::simpleMatch(tok, "; {")) - { - tok = tok->next()->link(); - } - - // skip executing scopes (ticket #1985).. - if (Token::simpleMatch(tok, "try {")) - { - tok = tok->next()->link(); - while (Token::simpleMatch(tok, "} catch (")) + // template variable or type.. + if (Token::Match(tok, "%type% <")) { - tok = tok->tokAt(2)->link(); - if (Token::simpleMatch(tok, ") {")) - tok = tok->next()->link(); - } - } + // these are used types.. + std::set usedtypes; - // not start of statement? - if (tok->previous() && !Token::Match(tok, "[;{}]")) - continue; - - // skip starting tokens.. ;;; typedef typename foo::bar::.. - while (Token::Match(tok, "[;{}]")) - tok = tok->next(); - while (Token::Match(tok, "typedef|typename")) - tok = tok->next(); - while (Token::Match(tok, "%type% ::")) - tok = tok->tokAt(2); - if (!tok) - break; - - // template variable or type.. - if (Token::Match(tok, "%type% <")) - { - // these are used types.. - std::set usedtypes; - - // parse this statement and see if the '<' and '>' are matching - unsigned int level = 0; - for (const Token *tok2 = tok; tok2 && !Token::Match(tok2, "[;{}]"); tok2 = tok2->next()) - { - if (tok2->str() == "(") - tok2 = tok2->link(); - else if (tok2->str() == "<") + // parse this statement and see if the '<' and '>' are matching + unsigned int level = 0; + for (const Token *tok2 = tok; tok2 && !Token::Match(tok2, "[;{}]"); tok2 = tok2->next()) { - bool inclevel = false; - if (Token::simpleMatch(tok2->previous(), "operator <")) - ; - else if (level == 0) - inclevel = true; - else if (tok2->next()->isStandardType()) - inclevel = true; - else if (Token::simpleMatch(tok2, "< typename")) - inclevel = true; - else if (Token::Match(tok2->tokAt(-2), "<|, %type% <") && usedtypes.find(tok2->strAt(-1)) != usedtypes.end()) - inclevel = true; - else if (Token::Match(tok2, "< %type%") && usedtypes.find(tok2->strAt(1)) != usedtypes.end()) - inclevel = true; - else if (Token::Match(tok2, "< %type%")) + if (tok2->str() == "(") + tok2 = tok2->link(); + else if (tok2->str() == "<") { - // is the next token a type and not a variable/constant? - // assume it's a type if there comes another "<" - const Token *tok3 = tok2->next(); - while (Token::Match(tok3, "%type% ::")) - tok3 = tok3->tokAt(2); - if (Token::Match(tok3, "%type% <")) + bool inclevel = false; + if (Token::simpleMatch(tok2->previous(), "operator <")) + ; + else if (level == 0) inclevel = true; - } + else if (tok2->next()->isStandardType()) + inclevel = true; + else if (Token::simpleMatch(tok2, "< typename")) + inclevel = true; + else if (Token::Match(tok2->tokAt(-2), "<|, %type% <") && usedtypes.find(tok2->strAt(-1)) != usedtypes.end()) + inclevel = true; + else if (Token::Match(tok2, "< %type%") && usedtypes.find(tok2->strAt(1)) != usedtypes.end()) + inclevel = true; + else if (Token::Match(tok2, "< %type%")) + { + // is the next token a type and not a variable/constant? + // assume it's a type if there comes another "<" + const Token *tok3 = tok2->next(); + while (Token::Match(tok3, "%type% ::")) + tok3 = tok3->tokAt(2); + if (Token::Match(tok3, "%type% <")) + inclevel = true; + } - if (inclevel) + if (inclevel) + { + ++level; + if (Token::Match(tok2->tokAt(-2), "<|, %type% <")) + usedtypes.insert(tok2->strAt(-1)); + } + } + else if (tok2->str() == ">") { - ++level; - if (Token::Match(tok2->tokAt(-2), "<|, %type% <")) - usedtypes.insert(tok2->strAt(-1)); + if (level > 0) + --level; } } - else if (tok2->str() == ">") + if (level > 0) { - if (level > 0) - --level; + syntaxError(tok); + deallocateTokens(); + return false; } } - if (level > 0) - { - syntaxError(tok); - deallocateTokens(); - return false; - } } } @@ -2050,10 +2055,13 @@ bool Tokenizer::tokenize(std::istream &code, const char FileName[], const std::s // Change initialisation of variable to assignment simplifyInitVar(); - setVarId(); + if (!preprocessorCondition) + { + setVarId(); - // Change initialisation of variable to assignment - simplifyInitVar(); + // Change initialisation of variable to assignment + simplifyInitVar(); + } _tokens->assignProgressValues(); diff --git a/lib/tokenize.h b/lib/tokenize.h index 54f438a05..6e0a85e64 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -68,7 +68,10 @@ public: * @param configuration E.g. "A" for code where "#ifdef A" is true * @return false if Source code contains syntax errors */ - bool tokenize(std::istream &code, const char FileName[], const std::string &configuration = ""); + bool tokenize(std::istream &code, + const char FileName[], + const std::string &configuration = "", + const bool preprocessorCondition = false); /** * Create tokens from code. diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 5dcee6329..af080fc11 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -110,6 +110,7 @@ private: TEST_CASE(if_cond8); TEST_CASE(if_cond9); TEST_CASE(if_cond10); + TEST_CASE(if_cond11); TEST_CASE(if_or_1); TEST_CASE(if_or_2); @@ -1067,6 +1068,22 @@ private: preprocessor.preprocess(istr, actual, "file.c"); } + void if_cond11() + { + errout.str(""); + const char filedata[] = "#if defined(L_fixunssfdi) && LIBGCC2_HAS_SF_MODE\n" + "#if LIBGCC2_HAS_DF_MODE\n" + "#elif FLT_MANT_DIG < W_TYPE_SIZE\n" + "#endif\n" + "#endif\n"; + std::istringstream istr(filedata); + std::map actual; + Settings settings; + Preprocessor preprocessor(&settings, this); + preprocessor.preprocess(istr, actual, "file.c"); + ASSERT_EQUALS("", errout.str()); + } + void if_or_1()