Fixed #1975 (segmentation fault of cppcheck)

This commit is contained in:
Daniel Marjamäki 2010-09-02 23:01:12 +02:00
parent 190a0040b7
commit 427c0f4bfd
4 changed files with 119 additions and 91 deletions

View File

@ -919,7 +919,7 @@ std::list<std::string> Preprocessor::getcfgs(const std::string &filedata, const
{ {
Tokenizer tokenizer(_settings, _errorLogger); Tokenizer tokenizer(_settings, _errorLogger);
std::istringstream tempIstr(s.c_str()); std::istringstream tempIstr(s.c_str());
if (!tokenizer.tokenize(tempIstr, filename.c_str())) if (!tokenizer.tokenize(tempIstr, filename.c_str(), "", true))
{ {
std::ostringstream lineStream; std::ostringstream lineStream;
lineStream << __LINE__; lineStream << __LINE__;
@ -1053,7 +1053,7 @@ void Preprocessor::simplifyCondition(const std::map<std::string, std::string> &v
{ {
Tokenizer tokenizer; Tokenizer tokenizer;
std::istringstream istr(("(" + condition + ")").c_str()); std::istringstream istr(("(" + condition + ")").c_str());
tokenizer.tokenize(istr, ""); tokenizer.tokenize(istr, "", "", true);
if (Token::Match(tokenizer.tokens(), "( %var% )")) if (Token::Match(tokenizer.tokens(), "( %var% )"))
{ {

View File

@ -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; _configuration = configuration;
@ -1704,7 +1707,6 @@ bool Tokenizer::tokenize(std::istream &code, const char FileName[], const std::s
createTokens(code); createTokens(code);
// remove inline SQL (Oracle PRO*C). Ticket: #1959 // remove inline SQL (Oracle PRO*C). Ticket: #1959
for (Token *tok = _tokens; tok; tok = tok->next()) 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.. // check for more complicated syntax errors when using templates..
for (const Token *tok = _tokens; tok; tok = tok->next()) if (!preprocessorCondition)
{ {
// skip executing scopes.. for (const Token *tok = _tokens; tok; tok = tok->next())
if (Token::Match(tok, ") const| {"))
{ {
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->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).. // template variable or type..
if (Token::simpleMatch(tok, "; {")) if (Token::Match(tok, "%type% <"))
{
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(); // these are used types..
if (Token::simpleMatch(tok, ") {")) std::set<std::string> usedtypes;
tok = tok->next()->link();
}
}
// not start of statement? // parse this statement and see if the '<' and '>' are matching
if (tok->previous() && !Token::Match(tok, "[;{}]")) unsigned int level = 0;
continue; for (const Token *tok2 = tok; tok2 && !Token::Match(tok2, "[;{}]"); tok2 = tok2->next())
// 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<std::string> 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() == "<")
{ {
bool inclevel = false; if (tok2->str() == "(")
if (Token::simpleMatch(tok2->previous(), "operator <")) tok2 = tok2->link();
; else if (tok2->str() == "<")
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? bool inclevel = false;
// assume it's a type if there comes another "<" if (Token::simpleMatch(tok2->previous(), "operator <"))
const Token *tok3 = tok2->next(); ;
while (Token::Match(tok3, "%type% ::")) else if (level == 0)
tok3 = tok3->tokAt(2);
if (Token::Match(tok3, "%type% <"))
inclevel = true; 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 (level > 0)
if (Token::Match(tok2->tokAt(-2), "<|, %type% <")) --level;
usedtypes.insert(tok2->strAt(-1));
} }
} }
else if (tok2->str() == ">") if (level > 0)
{ {
if (level > 0) syntaxError(tok);
--level; 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 // Change initialisation of variable to assignment
simplifyInitVar(); simplifyInitVar();
setVarId(); if (!preprocessorCondition)
{
setVarId();
// Change initialisation of variable to assignment // Change initialisation of variable to assignment
simplifyInitVar(); simplifyInitVar();
}
_tokens->assignProgressValues(); _tokens->assignProgressValues();

View File

@ -68,7 +68,10 @@ public:
* @param configuration E.g. "A" for code where "#ifdef A" is true * @param configuration E.g. "A" for code where "#ifdef A" is true
* @return false if Source code contains syntax errors * @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. * Create tokens from code.

View File

@ -110,6 +110,7 @@ private:
TEST_CASE(if_cond8); TEST_CASE(if_cond8);
TEST_CASE(if_cond9); TEST_CASE(if_cond9);
TEST_CASE(if_cond10); TEST_CASE(if_cond10);
TEST_CASE(if_cond11);
TEST_CASE(if_or_1); TEST_CASE(if_or_1);
TEST_CASE(if_or_2); TEST_CASE(if_or_2);
@ -1067,6 +1068,22 @@ private:
preprocessor.preprocess(istr, actual, "file.c"); 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<std::string, std::string> actual;
Settings settings;
Preprocessor preprocessor(&settings, this);
preprocessor.preprocess(istr, actual, "file.c");
ASSERT_EQUALS("", errout.str());
}
void if_or_1() void if_or_1()